前置知识: Python

Python与Django

4 minIntermediate2026/6/14

Django Web框架

什么是 Django

Django 是一个全功能的 Python Web 框架,它遵循”内置电池”(batteries included)的理念,提供了开发 Web 应用所需的大部分功能:ORM、管理后台、表单处理、用户认证、URL 路由、模板引擎等。你不需要从零开始拼装各种组件,Django 开箱即用。

Django 特别适合内容管理系统、电商平台、社交网络等需要快速开发且功能丰富的 Web 应用。Instagram、Pinterest、Mozilla 等知名网站都使用 Django 构建。

基础概念

MVT 架构

Django 采用 MVT(Model-View-Template)架构:

  • Model(模型):定义数据结构,与数据库交互。每个模型对应一张数据库表
  • View(视):处理业务逻辑,接收请求并返回响应
  • Template(模板):负责页面展示,生成 HTML

ORM

Django 的 ORM(对象关系映射)让你用 Python 来操作数据库,不需要手写 SQL。你定义模型,Django 自动生成对应的数据库表,并提供查询接口

Admin 后台

Django 最强大的特性之一是自动生成的管理后台。只需定义模型,Django 就会自动创建一个功能完整的后台管理界面,支持增删改查、搜索、过滤等操作。

App

Django 项目由多个 App 组成。每个 App 是一个独立的功能模块,包含自己的模型、视模板等。App 可以复用到不同项目中。

快速上手

安装 Django

pip install django

创建项目

# 创建 Django 项目
django-admin startproject mysite

# 进入项目目录
cd mysite

# 创建一个 App
python manage.py startapp blog

项目结构:

mysite/
  manage.py           # 管理脚本
  mysite/
    settings.py       # 项目配置
    urls.py           # 根 URL 路由
    wsgi.py           # 部署入口
  blog/
    models.py         # 数据模型
    views.py          # 视图函数
    urls.py           # App 的 URL 路由
    admin.py          # Admin 后台配置

定义模型

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

class Article(models.Model):
    """文章模型"""
    title = models.CharField('标题', max_length=200)
    content = models.TextField('内容')
    author = models.CharField('作者', max_length=100)
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    is_published = models.BooleanField('是否发布', default=False)

    def __str__(self):
        return self.title

注册模型到 Admin

# blog/admin.py
from django.contrib import admin
from .models import Article

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    # 列表页显示的字段
    list_display = ['title', 'author', 'created_at', 'is_published']
    # 可过滤的字段
    list_filter = ['is_published', 'created_at']
    # 可搜索的字段
    search_fields = ['title', 'content']

创建并执行迁移

# 生成迁移文件
python manage.py makemigrations

# 执行迁移(创建数据库表)
python manage.py migrate

# 创建管理员账号
python manage.py createsuperuser

# 启动开发服务器
python manage.py runserver

访问 http://127.0.0.1:8000/admin/ 即可使用管理后台。

详细用法

编写视

Django 支持函数视两种方式:

# blog/views.py - 函数视图
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from .models import Article

def article_list(request):
    """文章列表"""
    articles = Article.objects.filter(is_published=True).order_by('-created_at')
    return render(request, 'blog/article_list.html', {'articles': articles})

def article_detail(request, pk):
    """文章详情"""
    article = get_object_or_404(Article, pk=pk, is_published=True)
    return render(request, 'blog/article_detail.html', {'article': article})

def article_api(request):
    """返回 JSON 格式的文章列表"""
    articles = Article.objects.filter(is_published=True).values('id', 'title', 'author')
    return JsonResponse(list(articles), safe=False)
# blog/views.py - 类视图(更简洁,推荐)
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .models import Article

class ArticleListView(ListView):
    """文章列表视图"""
    model = Article
    template_name = 'blog/article_list.html'
    context_object_name = 'articles'

    def get_queryset(self):
        # 只显示已发布的文章
        return Article.objects.filter(is_published=True).order_by('-created_at')

class ArticleDetailView(DetailView):
    """文章详情视图"""
    model = Article
    template_name = 'blog/article_detail.html'
    context_object_name = 'article'

class ArticleCreateView(CreateView):
    """创建文章视图"""
    model = Article
    fields = ['title', 'content', 'author', 'is_published']
    template_name = 'blog/article_form.html'
    success_url = '/blog/'

配置 URL 路由

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

urlpatterns = [
    path('', views.ArticleListView.as_view(), name='article_list'),
    path('<int:pk>/', views.ArticleDetailView.as_view(), name='article_detail'),
    path('create/', views.ArticleCreateView.as_view(), name='article_create'),
    path('api/', views.article_api, name='article_api'),
]
# mysite/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),  # 引入 blog 的路由
]

编写模板

<!-- blog/templates/blog/article_list.html -->
<html>
<head><title>文章列表</title></head>
<body>
  <h1>文章列表</h1>
  {% for article in articles %}
    <div>
      <h2><a href="{{ article.get_absolute_url }}">{{ article.title }}</a></h2>
      <p>作者: {{ article.author }} | 时间: {{ article.created_at|date:"Y-m-d" }}</p>
    </div>
  {% empty %}
    <p>暂无文章</p>
  {% endfor %}
</body>
</html>

ORM 查询

from .models import Article

# 基本查询
articles = Article.objects.all()                          # 查询所有
article = Article.objects.get(pk=1)                       # 按 ID 查询
articles = Article.objects.filter(is_published=True)      # 条件过滤
articles = Article.objects.exclude(author='admin')        # 排除条件

# 链式查询
articles = Article.objects.filter(
    is_published=True
).exclude(
    title__contains='测试'
).order_by('-created_at')[:10]

# 常用查询条件
Article.objects.filter(title__contains='Python')          # 标题包含
Article.objects.filter(title__startswith='Python')        # 标题以...开头
Article.objects.filter(created_at__year=2026)             # 按年份过滤
Article.objects.filter(author__in=['张三', '李四'])        # 在列表中
Article.objects.filter(content__isnull=True)              # 内容为空

# 聚合查询
from django.db.models import Count, Avg
Article.objects.aggregate(total=Count('id'))              # 总数
Article.objects.values('author').annotate(count=Count('id'))  # 按作者分组统计

# 创建和更新
article = Article.objects.create(title='新文章', content='内容', author='张三')
article.title = '修改后的标题'
article.save()

# 删除
article.delete()
Article.objects.filter(is_published=False).delete()

表单处理

# blog/forms.py
from django import forms
from .models import Article

# 基于 Model 的表单
class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'content', 'author', 'is_published']
        widgets = {
            'content': forms.Textarea(attrs={'rows': 10}),
        }

# 自定义表单
class ContactForm(forms.Form):
    name = forms.CharField(label='姓名', max_length=100)
    email = forms.EmailField(label='邮箱')
    message = forms.CharField(label='留言', widget=forms.Textarea)
# blog/views.py - 表单处理视图
def contact(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            message = form.cleaned_data['message']
            # 处理表单数据(如发送邮件)
            return render(request, 'blog/contact_success.html')
    else:
        form = ContactForm()
    return render(request, 'blog/contact.html', {'form': form})

用户认证

Django 内置了完整的用户认证系统:

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect

def login_view(request):
    """用户登录"""
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)
            return redirect('home')
        else:
            return render(request, 'login.html', {'error': '用户名或密码错误'})
    return render(request, 'login.html')

def logout_view(request):
    """用户登出"""
    logout(request)
    return redirect('home')

# 使用装饰器保护视图
@login_required
def profile(request):
    """用户资料(需要登录才能访问)"""
    return render(request, 'profile.html')

常见场景

Django REST Framework 构建 API

pip install djangorestframework
# blog/serializers.py
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Article
        fields = ['id', 'title', 'content', 'author', 'created_at', 'is_published']
# blog/api_views.py
from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    """文章 API 视图集(自动提供增删改查接口)"""
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
# blog/urls.py - 添加 API 路由
from rest_framework.routers import DefaultRouter
from .api_views import ArticleViewSet

router = DefaultRouter()
router.register('api/articles', ArticleViewSet)

urlpatterns = [
    # ... 其他路由
    path('', include(router.urls)),
]

注意事项与常见错误

settings.py 中的 DEBUG 模式

生产环境必须设置 DEBUG=False,否则会暴露敏感信息。同时需要配置 ALLOWED_HOSTS:

# 生产环境配置
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']

静态文件收集

开发时 Django 自动处理静态文件,但生产环境需要运行 collectstatic:

python manage.py collectstatic

N+1 查询问题

模板中遍历关联对象时,可能会产生大量额外查询。使用 select_related 或 prefetch_related 优化:

# 不好的做法:每个文章都会额外查询一次作者信息
articles = Article.objects.all()

# 好的做法:一次性关联查询
articles = Article.objects.select_related('author').all()

# 多对多关系用 prefetch_related
articles = Article.objects.prefetch_related('tags').all()

不要在视中写复杂逻辑

应该保持简洁,复杂的业务逻辑应该放在模型的方法或单独的服务层中。

进阶用法

自定义中间件

# middleware.py
class SimpleLogMiddleware:
    """简单的请求日志中间件"""
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 请求前的处理
        print(f"请求: {request.method} {request.path}")
        response = self.get_response(request)
        # 响应后的处理
        print(f"响应状态: {response.status_code}")
        return response

在 settings.py 中注册:

MIDDLEWARE = [
    # ...
    'myapp.middleware.SimpleLogMiddleware',
]

信号

Django 信号允许你在某些动作发生时自动执行代码:

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Article

@receiver(post_save, sender=Article)
def on_article_created(sender, instance, created, **kwargs):
    """文章创建后自动执行"""
    if created:
        print(f"新文章已创建: {instance.title}")
        # 可以在这里发送通知等

使用 Django 配合 Celery

# tasks.py
from celery import shared_task

@shared_task
def send_notification_email(article_id):
    """异步发送通知邮件"""
    from .models import Article
    article = Article.objects.get(pk=article_id)
    # 发送邮件的逻辑
    print(f"已发送通知: {article.title}")

在模型中触发异步任务:

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Article
from .tasks import send_notification_email

@receiver(post_save, sender=Article)
def notify_subscribers(sender, instance, created, **kwargs):
    if created and instance.is_published:
        send_notification_email.delay(instance.id)