DevToolBox免费
博客

Django指南:模型、视图、DRF REST API和部署

14 分钟阅读作者 DevToolBox

TL;DR

Django 是 Python 中最完整的 Web 框架——内置 ORM、管理面板、认证、迁移和模板系统,开箱即用。需要快速开发关系型数据库应用时选择 Django。使用 DRF(Django REST Framework)构建 API。生产环境使用 Gunicorn + Nginx 部署,所有密钥使用环境变量管理。切勿在生产环境中使用 DEBUG=True。

核心要点

  • 使用 python -m venv 创建虚拟环境,始终将依赖记录在 requirements.txt 或 pyproject.toml 中。
  • Django ORM 的 select_related() 和 prefetch_related() 是解决 N+1 查询问题的关键工具。
  • 生产环境必须设置 DEBUG=False、配置 ALLOWED_HOSTS 并使用环境变量管理 SECRET_KEY。
  • Django REST Framework 的 ViewSet + Router 组合可以用最少的代码生成完整的 CRUD API。
  • 使用 collectstatic 和 WhiteNoise(开发/小规模)或 Nginx(生产)提供静态文件。
  • 数据库迁移文件必须提交到版本控制,并在部署时在启动应用之前运行。

1. 什么是 Django?

Django 是一个用 Python 编写的高级 Web 框架,由 Adrian Holovaty 和 Simon Willison 于 2003 年在 Lawrence Journal-World 报社开发,2005 年开源发布。Django 的核心理念是"开箱即用"(batteries-included):框架内置了你构建现代 Web 应用所需的几乎一切——ORM(对象关系映射)、URL 路由、模板引擎、表单处理、认证系统、管理后台和安全防护。

Django 遵循 MTV(Model-Template-View)架构模式,这是 MVC 模式的变体:Model 负责数据结构和数据库交互,Template 负责展示层,View 负责业务逻辑和请求处理。Django 的 URL 配置(urls.py)相当于传统 MVC 中的 Controller 路由层。

Django 被 Instagram、Pinterest、Disqus、Mozilla、National Geographic 等知名网站和公司使用。它特别适合内容管理系统、电子商务平台、新闻网站和需要复杂数据关系的 Web 应用。

2. 安装与项目初始化

始终在虚拟环境中安装 Django,避免污染全局 Python 环境。以下是完整的项目初始化流程:

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install Django
pip install django djangorestframework
pip freeze > requirements.txt

# Create a new Django project
django-admin startproject myproject .

# Create an application inside the project
python manage.py startapp blog

# Run the development server
python manage.py runserver
# Visit http://127.0.0.1:8000/

项目创建后,需要在 settings.py 中注册新建的应用,并配置数据库连接:

# myproject/settings.py

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("SECRET_KEY", "django-insecure-dev-key-change-in-prod")

# SECURITY WARNING: do not run with debug turned on in production!
DEBUG = os.environ.get("DEBUG", "True") == "True"

ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",")

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",    # Django REST Framework
    "blog",              # Our application
]

# Database configuration (PostgreSQL recommended for production)
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.environ.get("DB_NAME", "mydb"),
        "USER": os.environ.get("DB_USER", "postgres"),
        "PASSWORD": os.environ.get("DB_PASSWORD", ""),
        "HOST": os.environ.get("DB_HOST", "localhost"),
        "PORT": os.environ.get("DB_PORT", "5432"),
    }
}

# Static files
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
MEDIA_URL = "/media/"
MEDIA_ROOT = BASE_DIR / "media"

3. 模型与 ORM

Django 的 ORM(Object-Relational Mapper)允许你用 Python 类定义数据库表结构,并通过 Python 对象操作数据,而无需编写 SQL。每个 Model 类对应数据库中的一张表,每个类属性对应一个数据库字段。

# blog/models.py

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone


class Category(models.Model):
    name = models.CharField(max_length=100, unique=True)
    slug = models.SlugField(max_length=100, unique=True)
    description = models.TextField(blank=True)

    class Meta:
        verbose_name_plural = "categories"
        ordering = ["name"]

    def __str__(self):
        return self.name


class Post(models.Model):
    STATUS_DRAFT = "draft"
    STATUS_PUBLISHED = "published"
    STATUS_CHOICES = [
        (STATUS_DRAFT, "Draft"),
        (STATUS_PUBLISHED, "Published"),
    ]

    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique_for_date="published_at")
    author = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="posts"
    )
    category = models.ForeignKey(
        Category, on_delete=models.SET_NULL, null=True, related_name="posts"
    )
    tags = models.ManyToManyField("Tag", blank=True, related_name="posts")
    body = models.TextField()
    status = models.CharField(
        max_length=10, choices=STATUS_CHOICES, default=STATUS_DRAFT
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    published_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ["-published_at"]
        indexes = [
            models.Index(fields=["status", "published_at"]),
            models.Index(fields=["author", "status"]),
        ]

    def __str__(self):
        return self.title

    def publish(self):
        self.status = self.STATUS_PUBLISHED
        self.published_at = timezone.now()
        self.save()


class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(max_length=50, unique=True)

    def __str__(self):
        return self.name

定义模型后,运行迁移命令创建数据库表:

# Generate migration files from model changes
python manage.py makemigrations blog

# Apply migrations to the database
python manage.py migrate

# View migration SQL without applying
python manage.py sqlmigrate blog 0001

Django QuerySet API 提供了强大的数据库查询接口:

# QuerySet API examples

from blog.models import Post, Category
from django.db.models import Count, Q, Prefetch

# Get all published posts
posts = Post.objects.filter(status="published")

# Chain filters
recent_posts = Post.objects.filter(
    status="published",
    published_at__year=2025
).order_by("-published_at")[:10]

# Complex Q object queries (OR conditions)
search_results = Post.objects.filter(
    Q(title__icontains="django") | Q(body__icontains="django")
)

# Avoid N+1: use select_related for ForeignKey
posts_with_author = Post.objects.select_related("author", "category").all()

# Avoid N+1: use prefetch_related for ManyToMany
posts_with_tags = Post.objects.prefetch_related("tags").all()

# Aggregation: count posts per category
categories_with_count = Category.objects.annotate(
    post_count=Count("posts", filter=Q(posts__status="published"))
).filter(post_count__gt=0)

# Update: bulk update without loading objects
Post.objects.filter(status="draft").update(status="archived")

# Get or create
category, created = Category.objects.get_or_create(
    slug="python",
    defaults={"name": "Python", "description": "Python programming"}
)

4. 视图与 URL 路由

Django 支持两种视图类型:函数视图(FBV)和类视图(CBV)。函数视图更简单直接,类视图通过继承提供代码复用。

# blog/views.py

from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from .models import Post


# Function-Based View (FBV)
def post_list(request):
    posts = Post.objects.filter(
        status="published"
    ).select_related("author", "category")[:20]
    return render(request, "blog/post_list.html", {"posts": posts})


# Class-Based View (CBV)
class PostListView(ListView):
    model = Post
    template_name = "blog/post_list.html"
    context_object_name = "posts"
    paginate_by = 20

    def get_queryset(self):
        return Post.objects.filter(
            status="published"
        ).select_related("author", "category")


class PostDetailView(DetailView):
    model = Post
    template_name = "blog/post_detail.html"
    slug_field = "slug"

    def get_queryset(self):
        return Post.objects.filter(status="published")


class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ["title", "body", "category", "tags", "status"]
    template_name = "blog/post_form.html"

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)


# FBV with login required decorator
@login_required
def post_publish(request, pk):
    post = get_object_or_404(Post, pk=pk, author=request.user)
    post.publish()
    return JsonResponse({"status": "published", "id": post.pk})

URL 配置将 URL 模式映射到视图函数:

# blog/urls.py

from django.urls import path
from . import views

app_name = "blog"  # Namespace for URL reversing

urlpatterns = [
    path("", views.PostListView.as_view(), name="post-list"),
    path("<slug:slug>/", views.PostDetailView.as_view(), name="post-detail"),
    path("create/", views.PostCreateView.as_view(), name="post-create"),
    path("<int:pk>/publish/", views.post_publish, name="post-publish"),
]


# myproject/urls.py (root URL configuration)

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path("admin/", admin.site.urls),
    path("blog/", include("blog.urls", namespace="blog")),
    path("api/", include("blog.api_urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

5. 模板系统(DTL)

Django 模板语言(DTL)是一个功能完整的模板引擎,支持模板继承、自定义标签和过滤器。推荐的目录结构是在每个应用下创建 templates/app_name/ 子目录。

{# templates/base.html — base template using template inheritance #}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}My Blog{% endblock %}</title>
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/main.css' %}">
</head>
<body>
    <nav>...</nav>
    <main>
        {% block content %}
        {% endblock %}
    </main>
    <footer>...</footer>
</body>
</html>


{# templates/blog/post_list.html — child template #}
{% extends "base.html" %}

{% block title %}Blog Posts | My Site{% endblock %}

{% block content %}
<h1>Latest Posts</h1>

{# Loop through posts from context #}
{% for post in posts %}
  <article>
    <h2>
      <a href="{% url 'blog:post-detail' post.slug %}">{{ post.title }}</a>
    </h2>
    <p>By {{ post.author.get_full_name }} on {{ post.published_at|date:"N j, Y" }}</p>
    <p>{{ post.body|truncatewords:50 }}</p>
  </article>
{% empty %}
  <p>No posts yet.</p>
{% endfor %}

{# Pagination #}
{% if is_paginated %}
  {% if page_obj.has_previous %}
    <a href="?page={{ page_obj.previous_page_number }}">Previous</a>
  {% endif %}
  <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
  {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}">Next</a>
  {% endif %}
{% endif %}
{% endblock %}

6. Django REST Framework(DRF)

Django REST Framework(DRF)是构建 Django API 的标准库,提供序列化器、APIView、ViewSet、权限系统和可浏览 API 界面。安装后在 INSTALLED_APPS 中添加 "rest_framework"。

# blog/serializers.py

from rest_framework import serializers
from .models import Post, Category, Tag
from django.contrib.auth.models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["id", "username", "first_name", "last_name"]


class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ["id", "name", "slug"]


class PostListSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    category_name = serializers.CharField(
        source="category.name", read_only=True
    )
    tags = TagSerializer(many=True, read_only=True)
    tag_ids = serializers.PrimaryKeyRelatedField(
        source="tags", queryset=Tag.objects.all(),
        many=True, write_only=True
    )

    class Meta:
        model = Post
        fields = [
            "id", "title", "slug", "author", "category", "category_name",
            "tags", "tag_ids", "status", "published_at", "created_at"
        ]
        read_only_fields = ["author", "created_at"]

    def create(self, validated_data):
        tags = validated_data.pop("tags", [])
        post = Post.objects.create(**validated_data)
        post.tags.set(tags)
        return post

ViewSet 和 Router 是 DRF 中最高效的 API 构建方式:

# blog/api_views.py

from rest_framework import viewsets, permissions, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from .models import Post
from .serializers import PostListSerializer


class PostViewSet(viewsets.ModelViewSet):
    """Full CRUD API for posts."""
    queryset = Post.objects.select_related("author", "category").prefetch_related("tags")
    serializer_class = PostListSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ["status", "category", "author"]
    search_fields = ["title", "body"]
    ordering_fields = ["published_at", "created_at"]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

    @action(detail=True, methods=["post"],
            permission_classes=[permissions.IsAuthenticated])
    def publish(self, request, pk=None):
        post = self.get_object()
        if post.author != request.user:
            return Response({"error": "Not authorized"}, status=403)
        post.publish()
        return Response({"status": "published"})


# blog/api_urls.py

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .api_views import PostViewSet

router = DefaultRouter()
router.register(r"posts", PostViewSet)

urlpatterns = [
    path("", include(router.urls)),
]
# This generates:
# GET  /api/posts/           -> list
# POST /api/posts/           -> create
# GET  /api/posts/{id}/      -> retrieve
# PUT  /api/posts/{id}/      -> update
# PATCH /api/posts/{id}/     -> partial_update
# DELETE /api/posts/{id}/    -> destroy
# POST /api/posts/{id}/publish/ -> custom action

7. 认证与权限

Django 内置了完整的认证系统,包括用户模型、登录/登出视图、密码哈希和会话管理。对于 API,推荐使用 JWT(JSON Web Token)认证,使用 djangorestframework-simplejwt 库。

# Install JWT library
# pip install djangorestframework-simplejwt

# settings.py — configure JWT authentication

from datetime import timedelta

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework_simplejwt.authentication.JWTAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES": [
        "rest_framework.permissions.IsAuthenticatedOrReadOnly",
    ],
    "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
    "PAGE_SIZE": 20,
    "DEFAULT_THROTTLE_CLASSES": [
        "rest_framework.throttling.AnonRateThrottle",
        "rest_framework.throttling.UserRateThrottle",
    ],
    "DEFAULT_THROTTLE_RATES": {
        "anon": "100/hour",
        "user": "1000/hour",
    },
}

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=7),
    "ROTATE_REFRESH_TOKENS": True,
    "BLACKLIST_AFTER_ROTATION": True,
    "ALGORITHM": "HS256",
    "AUTH_HEADER_TYPES": ("Bearer",),
}


# urls.py — add JWT token endpoints

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
    TokenVerifyView,
)

urlpatterns += [
    path("api/auth/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
    path("api/auth/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
    path("api/auth/token/verify/", TokenVerifyView.as_view(), name="token_verify"),
]

DRF 提供细粒度的权限控制,可以自定义权限类:

# blog/permissions.py

from rest_framework import permissions


class IsAuthorOrReadOnly(permissions.BasePermission):
    """Allow only the author of an object to modify it."""

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request
        if request.method in permissions.SAFE_METHODS:
            return True
        # Write permissions only to the author
        return obj.author == request.user


class IsAdminOrReadOnly(permissions.BasePermission):
    """Allow only admin users to modify; read-only for others."""

    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return True
        return request.user and request.user.is_staff

8. 生产部署

生产部署 Django 的标准方案是:Gunicorn(WSGI 服务器)+ Nginx(反向代理)。Docker 使部署更加一致和可移植。以下是完整的 Docker 配置:

# Dockerfile

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    postgresql-client \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt

# Copy project
COPY . .

# Collect static files
RUN python manage.py collectstatic --noinput

EXPOSE 8000

CMD ["gunicorn", "myproject.wsgi:application", \
     "--bind", "0.0.0.0:8000", \
     "--workers", "4", \
     "--worker-class", "gthread", \
     "--threads", "2", \
     "--timeout", "60", \
     "--access-logfile", "-"]
# docker-compose.yml

version: "3.9"

services:
  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      POSTGRES_DB: ${DB_NAME}
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}

  redis:
    image: redis:7-alpine

  web:
    build: .
    command: >
      sh -c "python manage.py migrate &&
             gunicorn myproject.wsgi:application
             --bind 0.0.0.0:8000 --workers 4"
    volumes:
      - static_volume:/app/staticfiles
      - media_volume:/app/media
    env_file: .env
    depends_on:
      - db
      - redis

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - static_volume:/static
      - media_volume:/media
    depends_on:
      - web

volumes:
  postgres_data:
  static_volume:
  media_volume:
# nginx.conf

upstream django {
    server web:8000;
}

server {
    listen 80;
    server_name yourdomain.com;

    client_max_body_size 20M;

    location /static/ {
        alias /static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location /media/ {
        alias /media/;
    }

    location / {
        proxy_pass http://django;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

生产环境的 .env 文件应包含所有敏感配置,永远不要提交到版本控制:

# .env (add to .gitignore!)

SECRET_KEY=your-long-random-secret-key-here
DEBUG=False
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com

DB_NAME=mydb
DB_USER=dbuser
DB_PASSWORD=your-strong-db-password
DB_HOST=db
DB_PORT=5432

REDIS_URL=redis://redis:6379/0

EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_HOST_USER=apikey
EMAIL_HOST_PASSWORD=your-sendgrid-api-key
DEFAULT_FROM_EMAIL=noreply@yourdomain.com

9. Django vs Flask vs FastAPI vs Ruby on Rails

选择 Web 框架时,需要根据项目规模、团队经验、性能需求和生态系统来决策。以下对比四种主流框架的关键维度:

特性DjangoFlaskFastAPIRails
语言PythonPythonPythonRuby
类型全栈微框架API 框架全栈
内置 ORM
管理后台
自动迁移插件需 Alembic
REST APIDRFFlask-RESTful内置Native
异步支持Django 3.1+有限原生有限
性能(吞吐量)中等中等高(异步)中等
学习曲线中等中等
文档质量优秀良好优秀优秀
社区规模快速增长
适合场景全功能 Web 应用小型服务高性能 API快速原型

决策指南:如果你需要快速构建包含管理后台、用户认证和数据库操作的 Web 应用,选 Django。如果你在构建高并发的纯 API 服务,考虑 FastAPI。如果你需要最大灵活性或者项目非常简单,选 Flask。如果你的团队有 Ruby 背景或者在构建 SaaS MVP,选 Rails。

10. Django Admin 与信号系统

Django 自动生成的管理后台(Admin)是其最强大的特性之一。通过简单的配置,你可以获得功能完整的数据管理界面,支持搜索、过滤、批量操作和自定义视图。

# blog/admin.py

from django.contrib import admin
from .models import Post, Category, Tag


@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ["title", "author", "category", "status", "published_at"]
    list_filter = ["status", "category", "author", "created_at"]
    search_fields = ["title", "body"]
    prepopulated_fields = {"slug": ("title",)}
    raw_id_fields = ["author"]
    date_hierarchy = "published_at"
    ordering = ["-created_at"]
    actions = ["make_published", "make_draft"]

    @admin.action(description="Mark selected posts as published")
    def make_published(self, request, queryset):
        updated = queryset.update(status="published")
        self.message_user(request, f"{updated} posts marked as published.")

    @admin.action(description="Mark selected posts as draft")
    def make_draft(self, request, queryset):
        queryset.update(status="draft")


@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ["name", "slug"]
    prepopulated_fields = {"slug": ("name",)}


# Django Signals — decoupled event handling

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import send_mail


@receiver(post_save, sender=Post)
def notify_on_publish(sender, instance, created, **kwargs):
    """Send notification email when a post is published."""
    if not created and instance.status == "published":
        send_mail(
            subject=f"New post published: {instance.title}",
            message=f"Check out the new post: {instance.title}",
            from_email="noreply@example.com",
            recipient_list=["editor@example.com"],
            fail_silently=True,
        )

常见问题

Django 和 Flask 哪个更好?

Django 更适合需要完整功能的大型项目:内置 ORM、管理面板、认证系统和迁移工具。Flask 更适合小型微服务或需要高度定制的场景。如果你在构建 CRUD 应用或需要快速搭建原型,Django 的"开箱即用"优势会节省大量时间。

Django ORM 性能如何?能处理大规模数据吗?

Django ORM 在大多数场景下性能出色,但需要注意 N+1 查询问题。使用 select_related() 处理 ForeignKey,使用 prefetch_related() 处理 ManyToMany 关系。对于复杂查询可以使用 .raw() 或 django.db.connection.cursor()。配合数据库索引和 QuerySet 的 .only()/.defer() 进一步优化。

Django REST Framework 和 FastAPI 如何选择?

如果你的应用需要高并发异步处理(如 WebSocket、实时数据流)或者只需要构建轻量级 API 而不需要 Django 其他功能,FastAPI 是更好的选择。如果你已经在使用 Django 或需要 Django 的 ORM、Admin、Auth 等功能,DRF 是自然的选择,集成更紧密。

如何在 Django 中处理大文件上传?

对于大文件上传,在 settings.py 中设置 FILE_UPLOAD_MAX_MEMORY_SIZE 和 DATA_UPLOAD_MAX_MEMORY_SIZE。使用 FileField 或 ImageField 存储文件,生产环境推荐配合 django-storages 将文件存储到 S3 或其他云存储。使用 chunked uploads(分块上传)处理超大文件,可以考虑 django-chunked-upload 库。

Django 如何做数据库迁移?

Django 的迁移系统会自动检测 models.py 的变更并生成迁移文件。使用 makemigrations 生成迁移文件,migrate 执行迁移。迁移文件应提交到版本控制中。生产环境部署时,在启动应用前运行 migrate。如需回滚,使用 migrate app_name migration_number 指定迁移版本。

如何在 Django 中实现缓存?

Django 支持多种缓存后端:内存缓存(适合开发)、Memcached 和 Redis(适合生产)。使用 django-redis 集成 Redis 缓存。可以缓存整个视图(@cache_page)、模板片段({% cache %})或手动使用 cache.get()/cache.set()。数据库查询结果缓存是最常见的优化点。

Django 支持异步视图吗?

从 Django 3.1 开始,Django 支持异步视图、中间件和 ORM 操作。使用 async def 定义异步视图,配合 ASGI 服务器(如 Daphne 或 Uvicorn)运行。注意:Django ORM 的异步支持需要使用 sync_to_async 包装同步 ORM 调用,或使用原生异步 ORM 方法(Django 4.1+)。

Django 项目如何处理多租户(Multi-tenancy)?

Django 多租户主要有三种方案:1) 行级隔离:每个模型添加 tenant 外键,查询时过滤;2) Schema 隔离:每个租户独立的 PostgreSQL schema,使用 django-tenant-schemas 或 django-tenants 库;3) 独立数据库:每个租户独立数据库,使用 Django 的多数据库路由。大多数 SaaS 应用推荐方案 2,兼顾隔离性和资源效率。

总结

Django 是 Python 生态中最成熟、最完整的 Web 框架。其"开箱即用"的设计哲学让开发者可以专注于业务逻辑而非基础设施。核心要点:使用虚拟环境管理依赖,优化 ORM 查询避免 N+1 问题,使用 DRF 构建标准化的 REST API,生产环境使用 Docker + Gunicorn + Nginx,始终通过环境变量管理密钥。掌握 Django 将让你有能力独立构建从简单博客到复杂电商平台的任何 Web 应用。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

{ }JSON Formatter#Hash GeneratorB→Base64 Encoder

相关文章

Python异步/等待指南:asyncio、aiohttp、FastAPI和测试

掌握Python asyncio异步编程。含async/await基础、Tasks、aiohttp客户端/服务器、FastAPI集成、asyncpg、并发模式、同步/异步桥接和pytest-asyncio完整指南。

微服务指南:架构、通信模式和最佳实践

掌握微服务架构。涵盖服务通信(REST/gRPC/Kafka)、API网关、服务发现、分布式追踪、CQRS、Saga模式、Docker、Kubernetes和可观测性。

PostgreSQL完整指南:SQL、索引、JSONB和性能优化

掌握PostgreSQL的完整指南。含核心SQL、索引、Node.js pg、Prisma ORM、Python asyncpg、JSONB、全文搜索、窗口函数和性能调优。