Skip to main content

django-patterns

Django 架构模式、使用 DRF 的 REST API 设计、ORM 最佳实践、缓存、信号(Signals)、中间件(Middleware)以及生产级 Django 应用。 Use when this capability is needed.

Jump to install

Source facts

Repository
tomevault-io/tomes
Last source activity
July 23, 2026 at 21:48
Detected SKILL.md language
Chinese
Stars
1
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
django-patterns
description
Django 架构模式、使用 DRF 的 REST API 设计、ORM 最佳实践、缓存、信号(Signals)、中间件(Middleware)以及生产级 Django 应用。 Use when this capability is needed.
metadata
{"author":"codelably"}
# Django 开发模式 适用于可扩展、可维护应用程序的生产级 Django 架构模式。 ## 何时激活 - 构建 Django Web 应用程序时 - 设计 Django REST Framework (DRF) API 时 - 处理 Django ORM 和模型时 - 设置 Django 项目结构时 - 实现缓存(Caching)、信号(Signals)、中间件(Middleware)时 ## 项目结构 ### 推荐布局 ``` myproject/ ├── config/ │ ├── __init__.py │ ├── settings/ │ │ ├── __init__.py │ │ ├── base.py # 基础设置 │ │ ├── development.py # 开发环境设置 │ │ ├── production.py # 生产环境设置 │ │ └── test.py # 测试环境设置 │ ├── urls.py │ ├── wsgi.py │ └── asgi.py ├── manage.py └── apps/ ├── __init__.py ├── users/ │ ├── __init__.py │ ├── models.py │ ├── views.py │ ├── serializers.py │ ├── urls.py │ ├── permissions.py │ ├── filters.py │ ├── services.py │ └── tests/ └── products/ └── ... ``` ### 分离设置模式(Split Settings Pattern) ```python # config/settings/base.py from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent.parent SECRET_KEY = env('DJANGO_SECRET_KEY') DEBUG = False ALLOWED_HOSTS = [] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'rest_framework.authtoken', 'corsheaders', # 本地应用 'apps.users', 'apps.products', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'config.urls' WSGI_APPLICATION = 'config.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': env('DB_NAME'), 'USER': env('DB_USER'), 'PASSWORD': env('DB_PASSWORD'), 'HOST': env('DB_HOST'), 'PORT': env('DB_PORT', default='5432'), } } # config/settings/development.py from .base import * DEBUG = True ALLOWED_HOSTS = ['localhost', '127.0.0.1'] DATABASES['default']['NAME'] = 'myproject_dev' INSTALLED_APPS += ['debug_toolbar'] MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware'] EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # config/settings/production.py from .base import * DEBUG = False ALLOWED_HOSTS = env.list('ALLOWED_HOSTS') SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True SECURE_HSTS_SECONDS = 31536000 SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_PRELOAD = True # 日志配置 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'WARNING', 'class': 'logging.FileHandler', 'filename': '/var/log/django/django.log', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'WARNING', 'propagate': True, }, }, } ``` ## 模型设计模式 ### 模型最佳实践 ```python from django.db import models from django.contrib.auth.models import AbstractUser from django.core.validators import MinValueValidator, MaxValueValidator class User(AbstractUser): """扩展 AbstractUser 的自定义用户模型。""" email = models.EmailField(unique=True) phone = models.CharField(max_length=20, blank=True) birth_date = models.DateField(null=True, blank=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] class Meta: db_table = 'users' verbose_name = 'user' verbose_name_plural = 'users' ordering = ['-date_joined'] def __str__(self): return self.email def get_full_name(self): return f"{self.first_name} {self.last_name}".strip() class Product(models.Model): """带有适当字段配置的产品模型。""" name = models.CharField(max_length=200) slug = models.SlugField(unique=True, max_length=250) description = models.TextField(blank=True) price = models.DecimalField( max_digits=10, decimal_places=2, validators=[MinValueValidator(0)] ) stock = models.PositiveIntegerField(default=0) is_active = models.BooleanField(default=True) category = models.ForeignKey( 'Category', on_delete=models.CASCADE, related_name='products' ) tags = models.ManyToManyField('Tag', blank=True, related_name='products') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = 'products' ordering = ['-created_at'] indexes = [ models.Index(fields=['slug']), models.Index(fields=['-created_at']), models.Index(fields=['category', 'is_active']), ] constraints = [ models.CheckConstraint( check=models.Q(price__gte=0), name='price_non_negative' ) ] def __str__(self): return self.name def save(self, *args, **kwargs): if not self.slug: self.slug = slugify(self.name) super().save(*args, **kwargs) ``` ### QuerySet 最佳实践 ```python from django.db import models class ProductQuerySet(models.QuerySet): """Product 模型的自定义 QuerySet。""" def active(self): """仅返回已激活的产品。""" return self.filter(is_active=True) def with_category(self): """使用 select_related 加载分类,避免 N+1 查询。""" return self.select_related('category') def with_tags(self): """使用 prefetch_related 预加载多对多关系的标签。""" return self.prefetch_related('tags') def in_stock(self): """返回库存 > 0 的产品。""" return self.filter(stock__gt=0) def search(self, query): """按名称或描述搜索产品。""" return self.filter( models.Q(name__icontains=query) | models.Q(description__icontains=query) ) class Product(models.Model): # ... 字段 ... objects = ProductQuerySet.as_manager() # 使用自定义 QuerySet # 用法 Product.objects.active().with_category().in_stock() ``` ### 管理器(Manager)方法 ```python class ProductManager(models.Manager): """用于复杂查询的自定义管理器。""" def get_or_none(self, **kwargs): """返回对象,或者在不存在时返回 None 而不是抛出 DoesNotExist。""" try: return self.get(**kwargs) except self.model.DoesNotExist: return None def create_with_tags(self, name, price, tag_names): """创建产品并关联标签。""" product = self.create(name=name, price=price) tags = [Tag.objects.get_or_create(name=name)[0] for name in tag_names] product.tags.set(tags) return product def bulk_update_stock(self, product_ids, quantity): """批量更新多个产品的库存。""" return self.filter(id__in=product_ids).update(stock=quantity) # 在模型中 class Product(models.Model): # ... 字段 ... custom = ProductManager() ``` ## Django REST Framework 模式 ### 序列化器(Serializer)模式 ```python from rest_framework import serializers from django.contrib.auth.password_validation import validate_password from .models import Product, User class ProductSerializer(serializers.ModelSerializer): """Product 模型的序列化器。""" category_name = serializers.CharField(source='category.name', read_only=True) average_rating = serializers.FloatField(read_only=True) discount_price = serializers.SerializerMethodField() class Meta: model = Product fields = [ 'id', 'name', 'slug', 'description', 'price', 'discount_price', 'stock', 'category_name', 'average_rating', 'created_at' ] read_only_fields = ['id', 'slug', 'created_at'] def get_discount_price(self, obj): """如果适用,计算折扣价。""" if hasattr(obj, 'discount') and obj.discount: return obj.price * (1 - obj.discount.percent / 100) return obj.price def validate_price(self, value): """确保价格非负。""" if value < 0: raise serializers.ValidationError("价格不能为负数。") return value class ProductCreateSerializer(serializers.ModelSerializer): """用于创建产品的序列化器。""" class Meta: model = Product fields = ['name', 'description', 'price', 'stock', 'category'] def validate(self, data): """多字段的自定义校验。""" if data['price'] > 10000 and data['stock'] > 100: raise serializers.ValidationError( "高价值产品不能有大量库存。" ) return data class UserRegistrationSerializer(serializers.ModelSerializer): """用户注册序列化器。""" password = serializers.CharField( write_only=True, required=True, validators=[validate_password], style={'input_type': 'password'} ) password_confirm = serializers.CharField(write_only=True, style={'input_type': 'password'}) class Meta: model = User fields = ['email', 'username', 'password', 'password_confirm'] def validate(self, data): """校验两次输入的密码是否一致。""" if data['password'] != data['password_confirm']: raise serializers.ValidationError({ "password_confirm": "密码字段不匹配。" }) return data def create(self, validated_data): """创建并保存加密后的密码。""" validated_data.pop('password_confirm') password = validated_data.pop('password') user = User.objects.create(**validated_data) user.set_password(password) user.save() return user ``` ### 视图集(ViewSet)模式 ```python from rest_framework import viewsets, status, filters from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated, IsAdminUser from django_filters.rest_framework import DjangoFilterBackend from .models import Product from .serializers import ProductSerializer, ProductCreateSerializer from .permissions import IsOwnerOrReadOnly from .filters import ProductFilter from .filters import ProductFilter from .services import ProductService class ProductViewSet(viewsets.ModelViewSet): """Product 模型的视图集。""" queryset = Product.objects.select_related('category').prefetch_related('tags') permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter] filterset_class = ProductFilter search_fields = ['name', 'description'] ordering_fields = ['price', 'created_at', 'name'] ordering = ['-created_at'] def get_serializer_class(self): """根据操作(action)返回适当的序列化器类。""" if self.action == 'create': return ProductCreateSerializer return ProductSerializer def perform_create(self, serializer): """在保存时关联当前用户上下文。""" serializer.save(created_by=self.request.user) @action(detail=False, methods=['get']) def featured(self, request): """返回推荐产品。""" featured = self.queryset.filter(is_featured=True)[:10] serializer = self.get_serializer(featured, many=True) return Response(serializer.data) @action(detail=True, methods=['post']) def purchase(self, request, pk=None): """购买产品。"""
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub