Django 社交网络应用教程

1. Django 简介和特性

Django 是一个高级 Python Web 框架,它鼓励快速开发和干净、实用的设计。Django 遵循 MVT(Model-View-Template)架构,提供了许多内置功能,如用户认证、内容管理、表单处理、缓存等。

主要特性:

  • ORM(对象关系映射):简化数据库操作。
  • 自动管理界面:快速生成管理后台。
  • URL 路由:灵活的 URL 设计。
  • 模板系统:强大的模板引擎。
  • 表单处理:简化表单创建和验证。
  • 安全性:内置安全机制,如 CSRF 保护。

2. 安装和环境设置

安装 Django

pip install django

创建项目

django-admin startproject social_network
cd social_network

运行开发服务器

python manage.py runserver

3. 项目结构和管理命令

项目结构

social_network/
    manage.py
    social_network/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

常用管理命令

  • 创建应用:python manage.py startapp app_name
  • 数据库迁移:python manage.py makemigrations 和 python manage.py migrate
  • 创建超级用户:python manage.py createsuperuser

4. MVT 架构

Model

  • 定义数据结构和行为。
  • 使用 ORM 进行数据库操作。

View

  • 处理业务逻辑。
  • 接收请求并返回响应。

Template

  • 负责展示数据。
  • 使用 Django 模板语言。

5. 第一个 Django 应用

创建应用

python manage.py startapp posts

定义模型

# posts/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

注册模型

# posts/admin.py
from django.contrib import admin
from .models import Post

admin.site.register(Post)

创建视图

# posts/views.py
from django.shortcuts import render
from .models import Post

def post_list(request):
    posts = Post.objects.all()
    return render(request, 'posts/post_list.html', {'posts': posts})

配置 URL

# posts/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
]

创建模板

<!-- posts/templates/posts/post_list.html -->
<h1>Posts</h1>
<ul>
    {% for post in posts %}
        <li>{{ post.title }}</li>
    {% endfor %}
</ul>

6. 模型定义和字段类型

常用字段类型

  • CharField:字符字段。
  • TextField:文本字段。
  • IntegerField:整数字段。
  • DateTimeField:日期时间字段。
  • ForeignKey:外键。
  • ManyToManyField:多对多关系。

示例

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

7. 数据库迁移

创建迁移文件

python manage.py makemigrations

应用迁移

python manage.py migrate

8. 查询集和管理器

查询集

  • all():获取所有对象。
  • filter():过滤对象。
  • exclude():排除特定对象。
  • order_by():排序对象。

管理器

  • 自定义管理器可以添加额外的方法。
class PostManager(models.Manager):
    def published(self):
        return self.filter(published=True)

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    published = models.BooleanField(default=False)

    objects = PostManager()

9. 模型关系

一对多关系

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)

多对多关系

class Tag(models.Model):
    name = models.CharField(max_length=50)

class Article(models.Model):
    title = models.CharField(max_length=200)
    tags = models.ManyToManyField(Tag)

10. 自定义模型方法

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()

    def get_summary(self):
        return self.content[:100]

11. 函数视图和类视图

函数视图

def post_detail(request, post_id):
    post = get_object_or_404(Post, id=post_id)
    return render(request, 'posts/post_detail.html', {'post': post})

类视图

from django.views import View

class PostDetailView(View):
    def get(self, request, post_id):
        post = get_object_or_404(Post, id=post_id)
        return render(request, 'posts/post_detail.html', {'post': post})

12. URL 模式和命名

URL 模式

urlpatterns = [
    path('posts/', views.post_list, name='post_list'),
    path('posts/<int:post_id>/', views.post_detail, name='post_detail'),
]

命名 URL

<a href="{% url 'post_detail' post.id %}">View Post</a>

13. 视图参数和请求处理

请求对象

def post_detail(request, post_id):
    if request.method == 'POST':
        # 处理 POST 请求
    else:
        # 处理 GET 请求

14. 通用视图

示例

from django.views.generic import ListView, DetailView

class PostListView(ListView):
    model = Post
    template_name = 'posts/post_list.html'
    context_object_name = 'posts'

class PostDetailView(DetailView):
    model = Post
    template_name = 'posts/post_detail.html'
    context_object_name = 'post'

15. 中间件

自定义中间件

class CustomMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 请求处理前的逻辑
        response = self.get_response(request)
        # 响应处理后的逻辑
        return response

16. 模板语法和标签

模板语法

<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>

模板标签

{% for post in posts %}
    <h2>{{ post.title }}</h2>
    <p>{{ post.content }}</p>
{% endfor %}

17. 模板继承

基础模板

<!-- base.html -->
<html>
<head>
    <title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
    <header>...</header>
    <main>
        {% block content %}{% endblock %}
    </main>
    <footer>...</footer>
</body>
</html>

子模板

<!-- post_list.html -->
{% extends 'base.html' %}

{% block title %}Posts{% endblock %}

{% block content %}
    <h1>Posts</h1>
    <ul>
        {% for post in posts %}
            <li>{{ post.title }}</li>
        {% endfor %}
    </ul>
{% endblock %}

18. 上下文处理器

自定义上下文处理器

# context_processors.py
def custom_context(request):
    return {'custom_var': 'Custom Value'}

配置上下文处理器

# settings.py
TEMPLATES = [
    {
        'OPTIONS': {
            'context_processors': [
                'social_network.context_processors.custom_context',
            ],
        },
    },
]

19. 自定义模板标签和过滤器

自定义过滤器

# templatetags/custom_filters.py
from django import template

register = template.Library()

@register.filter
def upper_case(value):
    return value.upper()

使用过滤器

{{ post.title|upper_case }}

20. 静态文件处理

配置静态文件

# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]

使用静态文件

{% load static %}
<link rel="stylesheet" href="{% static 'css/styles.css' %}">

21. Django Form 类

定义表单

from django import forms

class PostForm(forms.Form):
    title = forms.CharField(max_length=200)
    content = forms.CharField(widget=forms.Textarea)

使用表单

def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            # 处理表单数据
            title = form.cleaned_data['title']
            content = form.cleaned_data['content']
            Post.objects.create(title=title, content=content)
            return redirect('post_list')
    else:
        form = PostForm()
    return render(request, 'posts/create_post.html', {'form': form})

22. 表单验证

自定义验证

class PostForm(forms.Form):
    title = forms.CharField(max_length=200)
    content = forms.CharField(widget=forms.Textarea)

    def clean_title(self):
        title = self.cleaned_data['title']
        if len(title) < 5:
            raise forms.ValidationError("Title must be at least 5 characters long.")
        return title

23. ModelForm

定义 ModelForm

from django.forms import ModelForm

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']

使用 ModelForm

def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('post_list')
    else:
        form = PostForm()
    return render(request, 'posts/create_post.html', {'form': form})

24. 表单集 (Formsets)

定义表单集

from django.forms import formset_factory

PostFormSet = formset_factory(PostForm, extra=2)

使用表单集

def manage_posts(request):
    if request.method == 'POST':
        formset = PostFormSet(request.POST)
        if formset.is_valid():
            for form in formset:
                if form.cleaned_data:
                    form.save()
            return redirect('post_list')
    else:
        formset = PostFormSet()
    return render(request, 'posts/manage_posts.html', {'formset': formset})

25. 文件上传处理

配置文件上传

# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

定义模型

class Post(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    image = models.ImageField(upload_to='posts/')

处理文件上传

def create_post(request):
    if request.method == 'POST':
        form = PostForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('post_list')
    else:
        form = PostForm()
    return render(request, 'posts/create_post.html', {'form': form})

26. 用户认证系统

用户注册

from django.contrib.auth.forms import UserCreationForm

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('login')
    else:
        form = UserCreationForm()
    return render(request, 'registration/register.html', {'form': form})

用户登录

from django.contrib.auth import authenticate, login

def user_login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('post_list')
        else:
            # 处理错误
            pass
    return render(request, 'registration/login.html')

27. 自定义用户模型

定义自定义用户模型

from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)

配置自定义用户模型

# settings.py
AUTH_USER_MODEL = 'accounts.CustomUser'

28. 权限和组

定义权限

from django.contrib.auth.models import Permission

permission = Permission.objects.get(codename='can_publish')

分配权限

user.user_permissions.add(permission)

29. 登录、注销和注册视图

登录视图

from django.contrib.auth.views import LoginView

urlpatterns = [
    path('login/', LoginView.as_view(template_name='registration/login.html'), name='login'),
]

注销视图

from django.contrib.auth.views import LogoutView

urlpatterns = [
    path('logout/', LogoutView.as_view(), name='logout'),
]

注册视图

from django.contrib.auth.forms import UserCreationForm
from django.views.generic.edit import CreateView

class RegisterView(CreateView):
    form_class = UserCreationForm
    template_name = 'registration/register.html'
    success_url = '/login/'

30. 基于类的权限控制

权限检查

from django.contrib.auth.mixins import UserPassesTestMixin

class PostDetailView(UserPassesTestMixin, DetailView):
    model = Post
    template_name = 'posts/post