Python Django Web 开发完全指南:从项目创建到生产部署

小飞兽 Python 7 次阅读 2026-07-24

Introduction

Django 是 Python 最成熟的 Web 框架。本文从创建项目开始,详解 Django ORM、模板系统、表单验证、用户认证、中间件、API 开发、以及 Gunicorn + Nginx 生产部署的全部流程。

---

Django 项目创建

pip install django
django-admin startproject myproject
cd myproject
python manage.py startapp blog
python manage.py migrate
python manage.py runserver

模型定义(ORM)

# blog/models.py
from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
    def __str__(self): return self.name

class Post(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    content = models.TextField()
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    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

迁移数据库:python manage.py makemigrations blog && python manage.py migrate

视图函数

# blog/views.py
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from .models import Post

def post_list(request):
    posts = Post.objects.filter(is_published=True).order_by('-created_at')[:20]
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug, is_published=True)
    return render(request, 'blog/post_detail.html', {'post': post})

def api_posts(request):
    posts = Post.objects.filter(is_published=True).order_by('-created_at')[:20]
    return JsonResponse({'posts': [
        {'id': p.id, 'title': p.title, 'slug': p.slug, 'created_at': p.created_at.isoformat()}
        for p in posts
    ]})

URL 路由

# myproject/urls.py
from django.urls import path
from blog.views import post_list, post_detail, api_posts

urlpatterns = [
    path('', post_list, name='post_list'),
    path('post/<slug:slug>/', post_detail, name='post_detail'),
    path('api/posts/', api_posts, name='api_posts'),
]

模板系统

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

{% block content %}
{% for post in posts %}
<article>
    <h2><a href="{% url 'post_detail' post.slug %}">{{ post.title }}</a></h2>
    <p>{{ post.created_at|date:'Y-m-d' }} | {{ post.category.name }}</p>
    <p>{{ post.content|truncatewords:50 }}</p>
</article>
{% empty %}
<p>暂无文章</p>
{% endfor %}
{% endblock %}

表单与 CSRF

Django 所有 POST 表单都需要 {% csrf_token %}:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">提交</button>
</form>

中间件

# middleware.py
class UserAgentMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        request.device_type = 'mobile' if 'Mobile' in request.META.get('HTTP_USER_AGENT', '') else 'desktop'
        return self.get_response(request)

注册到 settings.py 的 MIDDLEWARE 列表。

用户认证

# views.py
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.decorators import login_required

def login_view(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user:
            login(request, user)
            return redirect('post_list')
    return render(request, 'blog/login.html')

@login_required
def dashboard(request):
    return render(request, 'blog/dashboard.html')

REST API(django-rest-framework)

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

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = ['id', 'title', 'slug', 'content', 'created_at']
        read_only_fields = ['id', 'created_at']

# blog/views.py
from rest_framework.viewsets import ModelViewSet
from .models import Post
from .serializers import PostSerializer

class PostViewSet(ModelViewSet):
    queryset = Post.objects.filter(is_published=True)
    serializer_class = PostSerializer
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'posts', PostViewSet)

生产部署(Gunicorn + Nginx)

pip install gunicorn
# 启动
gunicorn myproject.wsgi:application --bind 127.0.0.1:8000 --workers 4 --daemon
# 或者用 systemd 管理

Nginx 配置反向代理到 Gunicorn:

server {
    listen 80;
    server_name mysite.com;
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location /static/ {
        alias /var/www/mysite/static/;
    }
    location /media/ {
        alias /var/www/mysite/media/;
    }
}

settings.py 生产配置

DEBUG = False
ALLOWED_HOSTS = ['mysite.com', 'www.mysite.com']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mysite_db',
        'USER': 'dbuser',
        'PASSWORD': '***',
    }
}

STATIC_ROOT = '/var/www/mysite/static'
MEDIA_ROOT = '/var/www/mysite/media'

常见问题

Q1: Django 跟 Flask 怎么选?Django 是全功能框架,内置 ORM/Admin/认证,适合企业级应用。Flask 更轻量灵活,适合微服务和小型项目。

Q2: CSRF 错误怎么处理?所有 POST 表单加 {% csrf_token %},Ajax POST 请求在 headers 里加 X-CSRFToken。

Q3: 如何优化 Django 数据库查询?用 select_related()(JOIN)和 prefetch_related()(多对多)减少查询次数。

延伸阅读

  • Django ORM 高级查询
  • Django REST Framework 认证
  • Django + Docker 部署

---

作者:小马 | 绍大技术网 shaoda.net