名称: django-patterns 描述: Django 架构模式,包括 DRF、ORM 优化、信号、中间件和项目结构
Django 模式
项目结构
组织 Django 项目,清晰分离应用、共享工具和配置。
project/
config/
settings/
base.py
local.py
production.py
urls.py
wsgi.py
apps/
users/
models.py
serializers.py
views.py
services.py
selectors.py
urls.py
tests/
orders/
...
common/
models.py
permissions.py
pagination.py
将业务逻辑放在 services.py(写操作)和 selectors.py(读操作)中。视图应保持精简。
ORM 优化
# select_related 用于外键 / 一对一关系(SQL JOIN)
orders = Order.objects.select_related("customer", "customer__profile").all()
# prefetch_related 用于多对多 / 反向外键(单独查询)
authors = Author.objects.prefetch_related(
Prefetch("books", queryset=Book.objects.filter(published=True))
).all()
# 延迟加载不需要的字段
posts = Post.objects.defer("body", "metadata").filter(status="published")
# 使用 .only() 当你只需要少数几列时
emails = User.objects.only("id", "email").filter(is_active=True)
# 批量操作
Product.objects.bulk_create(products, batch_size=1000)
Product.objects.bulk_update(products, ["price", "stock"], batch_size=1000)
始终使用 django-debug-toolbar 或测试中的 connection.queries 检查查询。
Django REST Framework 序列化器
class OrderSerializer(serializers.ModelSerializer):
customer_name = serializers.CharField(source="customer.full_name", read_only=True)
items = OrderItemSerializer(many=True, read_only=True)
total = serializers.SerializerMethodField()
class Meta:
model = Order
fields = ["id", "customer_name", "items", "total", "created_at"]
read_only_fields = ["id", "created_at"]
def get_total(self, obj):
return sum(item.price * item.quantity for item in obj.items.all())
def validate(self, data):
if data.get("start_date") and data.get("end_date"):
if data["start_date"] >= data["end_date"]:
raise serializers.ValidationError("结束日期必须在开始日期之后")
return data
信号
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Order)
def order_created_handler(sender, instance, created, **kwargs):
if created:
send_order_confirmation.delay(instance.id)
update_inventory.delay(instance.id)
倾向于使用信号处理跨应用的副作用。对于相同应用逻辑,直接调用服务。
自定义中间件
import time
import logging
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
start = time.monotonic()
response = self.get_response(request)
duration = time.monotonic() - start
logger.info(f"{request.method} {request.path} {response.status_code} {duration:.3f}s")
return response
反模式
- 将业务逻辑放在视图或序列化器中,而不是服务层
- 在列表端点中使用
Model.objects.all()而不分页 - 由于缺少
select_related/prefetch_related导致的 N+1 查询 - 过度使用信号处理相同应用逻辑(使流程难以追踪)
- 在
settings.py中存储密钥,而不是环境变量 - 运行原始 SQL 而不使用参数化查询
检查列表
- [ ] 业务逻辑位于 services/selectors,而非视图中
- [ ] 所有列表查询在需要时使用
select_related或prefetch_related - [ ] 序列化器使用自定义
validate方法验证输入数据 - [ ] 设置拆分为 base/local/production 模块
- [ ] 在合并前审查迁移
- [ ] 批量操作用于批量插入/更新
- [ ] 自定义中间件遵循 WSGI 可调用模式
- [ ] 测试覆盖模型约束、序列化器验证和视图权限