3.2 django框架

一、引言:Django框架核心价值与应用场景

Django是一款基于Python的高级Web框架,遵循"电池已内置(Batteries Included) "的设计哲学------内置ORM、Admin后台、用户认证、表单验证等核心功能,让开发者无需重复造轮子,专注业务逻辑实现。

核心优势:

  • 高效开发:从原型到生产环境的快速迭代

  • 安全内置:默认防御XSS、CSRF、SQL注入等常见攻击

  • 生态完善:DRF(接口)、Celery(异步)、Channels(实时通信)等插件丰富

  • Admin后台:一行代码生成可配置的管理界面

适用场景:

• 中小型Web应用(如电商后台、内容管理系统)

• RESTful API服务(配合DRF)

• 内部管理系统(依赖Admin快速搭建)

• 不适用:高并发IO密集型场景(需结合异步框架如FastAPI)

二、设计阶段:奠定项目可维护性基础

设计阶段的核心是"结构化",避免后期重构成本。

2.1 项目结构设计:合理拆分App

Django的App是功能模块化的核心,遵循"单一职责"拆分:

markdown 复制代码
myproject/
├── myproject/          # 项目核心配置
│   ├── settings/       # 环境分离配置(关键!)
│   │   ├── base.py     # 基础配置(通用设置)
│   │   ├── dev.py      # 开发环境(DEBUG=True)
│   │   └── prod.py     # 生产环境(DEBUG=False)
│   ├── urls.py         # 主路由
│   └── wsgi.py
├── apps/               # 所有业务App统一存放
│   ├── user/           # 用户模块(注册、登录、权限)
│   ├── product/        # 商品模块
│   └── order/          # 订单模块
├── utils/              # 通用工具函数(装饰器、常量)
├── static/             # 静态文件(CSS/JS/图片)
├── media/              # 用户上传文件
├── templates/          # 全局模板(若用前后端不分离)
├── Dockerfile          # 容器化配置
└── requirements/       # 依赖分离
    ├── base.txt        # 通用依赖
    ├── dev.txt         # 开发依赖(pytest、django-debug-toolbar)
    └── prod.txt        # 生产依赖(gunicorn、psycopg2-binary)

最佳实践:

• 避免单App过大(如一个App包含用户、商品、订单所有功能)

• 配置文件按环境拆分,避免生产环境泄露敏感信息

• 通用工具函数放入utils,不重复编写

2.2 数据库设计:ORM模型规划与关系优化

Django ORM是核心亮点,设计模型时需兼顾性能与可读性:

实战示例:用户-商品-订单模型设计(apps/order/models.py)

python 复制代码
from django.db import models
from django.conf import settings

class Product(models.Model):
    """商品模型"""
    name = models.CharField(max_length=100, verbose_name="商品名称")
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="价格")
    stock = models.PositiveIntegerField(default=0, verbose_name="库存")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")


    class Meta:
        db_table = "tb_products"  # 自定义表名(避免默认复数)
        indexes = [models.Index(fields=["name"]),]  # 高频查询字段加索引
        verbose_name = "商品"
        verbose_name_plural = verbose_name



class Order(models.Model):
    """订单模型"""
    ORDER_STATUS = (
        ("pending", "待支付"),
        ("paid", "已支付"),
        ("cancelled", "已取消"),
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,  # 关联内置用户模型(可扩展)
        on_delete=models.CASCADE,
        related_name="orders",  # 反向查询:user.orders.all()
        verbose_name="下单用户"
    )
    product = models.ForeignKey(
        Product,
        on_delete=models.CASCADE,
        related_name="orders",
        verbose_name="商品"
    )
    quantity = models.PositiveIntegerField(default=1, verbose_name="购买数量")
    status = models.CharField(
        max_length=20,
        choices=ORDER_STATUS,
        default="pending",
        verbose_name="订单状态"
    )
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    class Meta:
        db_table = "tb_orders"
        indexes = [models.Index(fields=["user", "status"]),]  # 联合索引优化查询
        verbose_name = "订单"
        verbose_name_plural = verbose_name

数据库设计最佳实践:

• 用related_name定义反向查询名称(避免默认model_set)

• 高频查询字段(如user、status)添加索引,联合索引需注意字段顺序

• 避免使用TextField存储高频查询数据(检索效率低)

• 模型关系优先用ForeignKey(一对多),多对多需谨慎设计(必要时用中间表)

2.3 安全设计:提前规避风险

Django默认提供安全防护,但需在设计阶段强化:

• 权限设计:基于角色(RBAC),使用Django内置Group与Permission,或扩展django-guardian实现对象级权限

• 敏感数据:密码用Django内置哈希(PBKDF2),不存储明文;手机号、邮箱等加密存储

• 接口安全:RESTful API需加认证(JWT/Tokens)、频率限制(DRF Throttling)

三、编码阶段:高效且稳健的开发实践

3.1 代码规范:遵循PEP8与Django风格

• 命名规范:App名小写(如user)、模型类名首字母大写(UserProfile)、函数/变量小写下划线(get_user_info)

• 注释规范:模型、函数加文档字符串("""用户登录接口:验证用户名密码""")

• 工具依赖:用black自动格式化代码,flake8检查规范,isort排序导入包

3.2 ORM优化:避免性能坑

Django ORM便捷但易产生低效查询,核心优化点:

(1)避免N+1查询

反面示例(查询订单时循环查商品,产生1+N次查询):

低效:1次查所有订单 + N次查每个订单的商品

python 复制代码
orders = Order.objects.all()
for order in orders:
    print(order.product.name)  # 每次循环触发新查询
优化示例(用select_related预加载外键):
高效:1次SQL查询关联订单和商品
orders = Order.objects.select_related("product").all()
for order in orders:
    print(order.product.name)  # 无额外查询

(2)批量操作替代循环

反面示例(循环创建100条数据,100次SQL):

python 复制代码
for i in range(100):
    Product.objects.create(name=f"商品{i}", price=99.9)

优化示例(bulk_create批量创建,1次SQL):

python 复制代码
products = [Product(name=f"商品{i}", price=99.9) for i in range(100)]
Product.objects.bulk_create(products, batch_size=50)  # batch_size控制单次提交数量

(3)只查询需要的字段

只查name和price字段,减少数据传输

python 复制代码
products = Product.objects.only("name", "price").all()

排除不需要的大字段(如description)

python 复制代码
products = Product.objects.defer("description").all()

3.3 视图与序列化:DRF最佳用法

Django REST Framework(DRF)是构建API的利器,核心实践:

(1)序列化器(Serializer)分层

python 复制代码
#apps/product/serializers.py
from rest_framework import serializers
from .models import Product

#列表页序列化器:只返回精简字段
class ProductListSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["id", "name", "price"]

#详情页序列化器:返回完整字段
class ProductDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["id", "name", "price", "stock", "created_at"]

#创建/更新序列化器:添加校验逻辑
class ProductCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Product
        fields = ["name", "price", "stock"]

    def validate_price(self, value):
        """自定义校验:价格不能为负"""
        if value < 0:
            raise serializers.ValidationError("价格不能小于0")
        return value

(2)视图用ViewSet简化代码

python 复制代码
#apps/product/views.py
from rest_framework import viewsets, permissions
from .models import Product
from .serializers import (
    ProductListSerializer, ProductDetailSerializer, ProductCreateSerializer
)

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    permission_classes = [permissions.IsAuthenticated]  # 登录认证

    def get_serializer_class(self):
        """根据动作返回不同序列化器"""
        if self.action == "list":
            return ProductListSerializer
        elif self.action in ["create", "update", "partial_update"]:
            return ProductCreateSerializer
        return ProductDetailSerializer

    def get_queryset(self):
        """自定义查询逻辑:支持筛选、排序"""
        queryset = super().get_queryset()
        # 筛选:按价格区间
        min_price = self.request.query_params.get("min_price")
        if min_price:
            queryset = queryset.filter(price__gte=min_price)
        # 排序:按创建时间倒序
        return queryset.order_by("-created_at")

(3)路由注册用Router简化

python 复制代码
#myproject/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.product.views import ProductViewSet

router = DefaultRouter()
router.register(r"products", ProductViewSet)  # 自动生成CRUD路由

urlpatterns = [
    path("api/", include(router.urls)),
]

3.4 测试实践:Django + pytest

延续前文Python测试思路,Django测试推荐用pytest-django插件,聚焦核心场景:

python 复制代码
#tests/test_product_api.py
import pytest
from django.urls import reverse
from rest_framework.test import APIClient
from apps.product.models import Product

@pytest.fixture
def api_client():
    """测试夹具:初始化API客户端"""
    return APIClient()

@pytest.fixture
def test_product():
    """测试夹具:创建测试商品"""
    return Product.objects.create(name="测试商品", price=199.9, stock=100)

@pytest.mark.django_db  # 启用数据库
def test_product_list_api(api_client, test_product):
    """测试商品列表接口"""
    url = reverse("product-list")
    api_client.force_authenticate(user=None)  # 若接口无需登录可省略
    response = api_client.get(url)
    # 断言状态码和数据
    assert response.status_code == 200
    assert len(response.data) == 1
    assert response.data[0]["name"] == "测试商品"

@pytest.mark.django_db
def test_product_create_api(api_client):
    """测试商品创建接口"""
    url = reverse("product-list")
    data = {"name": "新商品", "price": 299.9, "stock": 50}
    response = api_client.post(url, data, format="json")
    assert response.status_code == 201  # 创建成功
    assert Product.objects.count() == 1
    assert Product.objects.first().name == "新商品"

执行测试并生成覆盖率:

shell 复制代码
pytest tests/ --cov=apps --cov-report=html

四、部署阶段:从开发到生产的平滑过渡

4.1 环境配置分离

核心原则:敏感配置不硬编码,用环境变量或配置文件分离:

(1)配置文件拆分

python 复制代码
# myproject/settings/base.py(通用配置)
import os
from pathlib import Path

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

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "rest_framework",
    "apps.product",
    "apps.user",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    # ...
]
# myproject/settings/dev.py(开发环境)
from .base import *

DEBUG = True
ALLOWED_HOSTS = ["localhost", "127.0.0.1"]

# 数据库:本地SQLite
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    }
}

# myproject/settings/prod.py(生产环境)
from .base import *
import os
from dotenv import load_dotenv  # 加载.env文件

load_dotenv()  # 读取环境变量

DEBUG = False
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")  # 从环境变量获取

# 数据库:PostgreSQL(生产推荐)
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.getenv("DB_NAME"),
        "USER": os.getenv("DB_USER"),
        "PASSWORD": os.getenv("DB_PASSWORD"),
        "HOST": os.getenv("DB_HOST"),
        "PORT": os.getenv("DB_PORT", "5432"),
    }
}

# 静态文件配置(生产环境用Nginx托管)
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"

# 安全配置
SECRET_KEY = os.getenv("SECRET_KEY")  # 敏感密钥从环境变量获取
CSRF_TRUSTED_ORIGINS = os.getenv("CSRF_TRUSTED_ORIGINS", "").split(",")
(2).env文件(生产环境,不提交Git)
SECRET_KEY=your_secure_secret_key
DB_NAME=django_prod
DB_USER=django_user
DB_PASSWORD=your_db_password
DB_HOST=db
ALLOWED_HOSTS=your-domain.com,www.your-domain.com
CSRF_TRUSTED_ORIGINS=https://your-domain.com

4.2 容器化部署:Docker + Docker Compose

用Docker实现环境一致性,避免"开发环境能跑,生产环境报错":

(1)Dockerfile

docker 复制代码
# 基础镜像:Python 3.10
FROM python:3.10-slim

# 设置工作目录
WORKDIR /app

# 安装依赖
COPY requirements/prod.txt .
RUN pip install --no-cache-dir -r prod.txt

# 复制项目文件
COPY . .

# 收集静态文件(生产环境)
RUN python manage.py collectstatic --noinput

# 暴露端口
EXPOSE 8000

# 启动命令(用gunicorn替代runserver,生产推荐)
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
(2)docker-compose.yml
version: "3.8"

services:
  web:
    build: .
    restart: always
    depends_on:
      - db
      - redis
    env_file: .env
    volumes:
      - media_volume:/app/media  # 持久化用户上传文件
    command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000

  db:
    image: postgres:14
    restart: always
    env_file: .env
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_DB=${DB_NAME}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}

  redis:
    image: redis:7
    restart: always
    volumes:
      - redis_data:/data

  nginx:
    image: nginx:1.23
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - static_volume:/app/staticfiles
      - media_volume:/app/media
      - ./nginx/certbot/conf:/etc/letsencrypt
    depends_on:
      - web

volumes:
  postgres_data:
  redis_data:
  static_volume:
  media_volume:
(3)Nginx配置(nginx/conf.d/default.conf)
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    # 重定向到HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name your-domain.com www.your-domain.com;

    # SSL证书配置(Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    # 静态文件托管(Nginx直接响应,减轻Django压力)
    location /static/ {
        alias /app/staticfiles/;
        expires 1d;  # 缓存1天
    }

    location /media/ {
        alias /app/media/;
        expires 1d;
    }

    # 反向代理到Django应用
    location / {
        proxy_pass http://web:8000;
        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;
    }
}
4.3 CI/CD流程:GitHub Actions自动化部署

实现"代码提交→自动测试→自动部署",示例.github/workflows/deploy.yml:
name: Django Deploy

on:
  push:
    branches: [ main ]  # 主分支提交触发

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.10"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements/dev.txt
      - name: Run tests
        run: |
          pytest tests/ --cov=apps

  deploy:
    needs: test  # 测试通过后执行部署
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd /path/to/your/project
            git pull origin main
            docker-compose down
            docker-compose up --build -d

4.4 性能与监控优化

• 缓存策略:用Redis缓存高频查询数据(如商品列表),配置Django缓存:

python 复制代码
# settings/prod.py
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://redis:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

• 日志配置:记录错误和访问日志,便于排查问题:

python 复制代码
# settings/prod.py
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "file": {
            "level": "ERROR",
            "class": "logging.FileHandler",
            "filename": BASE_DIR / "logs/django_error.log",
        },
    },
    "loggers": {
        "django": {
            "handlers": ["file"],
            "level": "ERROR",
            "propagate": True,
        },
    },
}

• 监控工具:用Sentry跟踪错误,Prometheus + Grafana监控性能,ELK栈分析日志。

五、Django最佳实践总结

  1. 设计层面:App拆分合理、数据库索引优化、提前考虑安全

  2. 编码层面:遵循PEP8、ORM避免N+1查询、DRF序列化器分层

  3. 测试层面:单元测试+API测试全覆盖,用pytest提高效率

  4. 部署层面:环境分离、容器化部署、CI/CD自动化、监控落地

  5. 安全层面:敏感配置不硬编码、接口加认证限流、定期更新Django版本

六、结语:Django生态扩展与进阶

Django的强大不仅在于核心功能,更在于丰富的生态:

• 异步任务:用Celery + Redis处理耗时操作(如发送邮件、生成报表)

• 实时通信:用Channels实现WebSocket(如聊天功能、实时通知)

• 搜索功能:集成Elasticsearch实现全文检索

• 前端集成:结合Vue/React,Django仅提供API服务

相关推荐
Learner2 小时前
Python异常处理
java·前端·python
hui函数2 小时前
Python系列Bug修复|如何解决 pip install 安装报错 Backend ‘setuptools.build_meta’ 不可用 问题
python·bug·pip
谢的2元王国2 小时前
prompt工程逐渐成为工作流的重要一部分:以下是一套多节点新闻处理外加事实增强的文章报告日志记录
python
寻星探路2 小时前
【算法通关】双指针技巧深度解析:从基础到巅峰(Java 最优解)
java·开发语言·人工智能·python·算法·ai·指针
向上的车轮2 小时前
如何选择Python IDE?
开发语言·ide·python
小北方城市网2 小时前
微服务接口设计实战指南:高可用、易维护的接口设计原则与规范
java·大数据·运维·python·微服务·fastapi·数据库架构
小鸡吃米…3 小时前
机器学习 - 亲和传播算法
python·机器学习·亲和传播
内存不泄露3 小时前
基于Django和Vue3的文件分享平台设计与实现
后端·python·django