django-models
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDjango Model Patterns
Django 模型模式
Core Philosophy: Fat Models, Thin Views
核心理念:胖模型、瘦视图
Business logic belongs in models and managers, not views. Views orchestrate workflows; models implement domain behavior. This principle creates testable, reusable code that stays maintainable as complexity grows.
Good: Model methods handle business rules, state transitions, validation
Bad: Views contain if/else logic for domain rules, calculate derived values
业务逻辑应放在 models 和 managers 中,而不是 views 中。 views 负责编排工作流;models 实现领域行为。这一原则能够创建可测试、可复用的代码,并在复杂度不断增长时保持可维护性。
良好做法:由 model 方法处理业务规则、状态转换和验证
不良做法:views 中包含针对领域规则的 if/else 逻辑,并计算派生值
Model Design
模型设计
Structure Your Models Around Domain Concepts
围绕领域概念组织模型
- Use /
TextChoicesfor status fields and enumsIntegerChoices - Add for canonical object URLs
get_absolute_url() - Include for readable representations
__str__() - Set proper in Meta for consistent default sorting
ordering - Add database indexes for frequently filtered/sorted fields
- Use abstract base models for shared fields (timestamps, soft deletes, etc.)
- 对状态字段和枚举使用 /
TextChoicesIntegerChoices - 添加 ,提供对象的规范 URL
get_absolute_url() - 包含 ,以提供易读的表示形式
__str__() - 在 Meta 中设置适当的 ,确保一致的默认排序
ordering - 为经常用于筛选或排序的字段添加数据库索引
- 使用抽象基模型复用共享字段(时间戳、软删除等)
Field Selection Guidelines
字段选择指南
- Use for optional text fields (avoid null)
blank=True, default="" - Use for optional foreign keys
null=True, blank=True - For unique optional fields, use to avoid collision issues
null=True - Leverage for flexible metadata (avoid creating many optional fields)
JSONField - Set appropriate based on actual data needs
max_length
- 对可选文本字段使用 (避免使用 null)
blank=True, default="" - 对可选外键使用
null=True, blank=True - 对唯一可选字段使用 ,以避免冲突问题
null=True - 使用 存储灵活的元数据(避免创建大量可选字段)
JSONField - 根据实际数据需求设置适当的
max_length
Encapsulate Business Logic in Model Methods
在 model 方法中封装业务逻辑
- State transitions: ,
post.publish()order.cancel() - Permission checks:
post.is_editable_by(user) - Complex calculations:
invoice.calculate_total() - Use properties for computed read-only values
- Specify when saving partial changes
update_fields
- 状态转换:、
post.publish()order.cancel() - 权限检查:
post.is_editable_by(user) - 复杂计算:
invoice.calculate_total() - 使用 property 表示只读的计算值
- 保存部分更改时指定
update_fields
QuerySet Patterns: The Power of Composition
QuerySet 模式:组合的力量
Custom QuerySet classes are your secret weapon. They make queries reusable, chainable, and testable.
自定义 QuerySet 类是你的秘密武器。 它们能够让查询变得可复用、可链式调用且易于测试。
Pattern: QuerySet as Manager
模式:将 QuerySet 作为 Manager
Define a QuerySet subclass with domain-specific filter methods
Attach it to your model: objects = YourQuerySet.as_manager()
Chain methods for composable queries定义一个包含领域特定筛选方法的 QuerySet 子类
将其附加到 model:objects = YourQuerySet.as_manager()
链式调用方法以组合查询Benefits
优势
- Reusable query logic across views, tasks, management commands
- Chainable methods enable expressive, readable queries
- Easy to test in isolation
- Encapsulates query complexity away from views
- 可在 views、tasks 和 management commands 中复用查询逻辑
- 链式方法支持表达性强、易读的查询
- 易于独立测试
- 将查询复杂度与 views 隔离
Common QuerySet Methods
常用的 QuerySet 方法
- Filtering by status/state
- Date range queries (recent, upcoming, expired)
- User-scoped queries (owned_by, visible_to)
- Combined lookups (published_and_recent)
- 按 status/state 筛选
- 日期范围查询(recent、upcoming、expired)
- 按用户限定查询(owned_by、visible_to)
- 组合查询条件(published_and_recent)
Query Optimization: Avoid N+1 Queries
查询优化:避免 N+1 查询
The Golden Rules
黄金规则
- select_related(): Use for ForeignKey and OneToOneField (creates SQL JOIN)
- prefetch_related(): Use for ManyToManyField and reverse ForeignKeys (separate query + Python join)
- only(): Load specific fields when you don't need the whole object
- defer(): Exclude heavy fields (TextField, JSONField) you won't use
- Prefetch() object: Customize prefetch with filters and select_related
- :用于 ForeignKey 和 OneToOneField(创建 SQL JOIN)
select_related() - :用于 ManyToManyField 和反向 ForeignKey(执行单独的查询并在 Python 中 join)
prefetch_related() - :当不需要整个 object 时,仅加载特定字段
only() - :排除不会使用的较重字段(TextField、JSONField)
defer() - 对象:使用 filters 和 select_related 自定义预取行为
Prefetch()
Efficient Counting and Existence Checks
高效计数与存在性检查
- Use instead of
.exists()orif queryset:if len(queryset): - Use instead of
.count()len(queryset.all()) - Both perform database-level operations without loading objects
- 使用 ,而不是
.exists()或if queryset:if len(queryset): - 使用 ,而不是
.count()len(queryset.all()) - 两者都会在数据库级别执行操作,而不会加载 objects
Aggregation and Annotation
聚合与注解
- : Add computed fields to each object (Count, Sum, Avg, etc.)
annotate() - : Compute values across entire queryset
aggregate() - Use expressions for database-level updates (
F())views=F('views') + 1 - Combine annotate with filter for "objects with at least N related items"
- :为每个 object 添加计算字段(Count、Sum、Avg 等)
annotate() - :计算整个 queryset 的值
aggregate() - 使用 表达式执行数据库级更新(
F())views=F('views') + 1 - 将 annotate 与 filter 结合,用于查询“至少包含 N 个关联项的 objects”
Managers vs QuerySets
Managers 与 QuerySets
Use QuerySets for chainable query logic.
Use Managers for model-level operations that don't return querysets.
Manager: Think "factory methods" -
QuerySet: Think "filters and transformations" -
User.objects.create_user()Post.objects.published().recent()Most of the time, you want a custom QuerySet, not a custom Manager.
使用 QuerySets 实现可链式调用的查询逻辑。
使用 Managers 执行不返回 querysets 的 model 级操作。
Manager:可理解为“工厂方法”——
QuerySet:可理解为“筛选和转换”——
User.objects.create_user()Post.objects.published().recent()大多数时候,你需要的是自定义 QuerySet,而不是自定义 Manager。
Signals: Use Sparingly
Signals:谨慎使用
Signals create implicit coupling and make code harder to follow. Prefer explicit method calls.
Signals 会产生隐式耦合,使代码更难理解。优先使用显式的方法调用。
When Signals Make Sense
适合使用 Signals 的场景
- Audit logging (track all changes to a model)
- Cache invalidation (clear cache when model changes)
- Decoupling apps (third-party app needs to react to your models)
- 审计日志(跟踪 model 的所有更改)
- 缓存失效(model 发生变化时清除缓存)
- 解耦 apps(第三方 app 需要对你的 models 作出响应)
When to Avoid Signals
应避免使用 Signals 的场景
- Business logic that should be in model methods
- Logic tightly coupled to the calling code (just call the function directly)
- Complex workflows (use explicit service layer instead)
Rule of thumb: If you control both the trigger and the reaction, don't use a signal.
- 本应放在 model 方法中的业务逻辑
- 与调用代码紧密耦合的逻辑(直接调用函数即可)
- 复杂的工作流(改用显式 service layer)
经验法则:如果你同时控制触发操作和响应操作,就不要使用 signal。
Migrations
Migrations
Workflow
工作流
- Run after model changes
makemigrations - Review generated migration files before applying
- Run to apply migrations
migrate - Migrations should be reversible when possible
- model 更改后运行
makemigrations - 应用前检查生成的 migration 文件
- 运行 应用 migrations
migrate - 尽可能让 migrations 可逆
Data Migrations
数据 Migrations
Create with . Use to access models (not direct imports). Write both forward and reverse operations.
makemigrations --empty app_nameapps.get_model()Use data migrations for: Populating new fields, transforming data, migrating between fields.
使用 创建。使用 访问 models(不要直接导入)。同时编写正向和反向操作。
makemigrations --empty app_nameapps.get_model()数据 migrations 的适用场景:填充新字段、转换数据、在字段之间迁移数据。
Anti-Patterns to Avoid
应避免的反模式
Query Anti-Patterns
查询反模式
- Iterating over objects and accessing relations without /
select_related()prefetch_related() - Using instead of
if queryset:.exists() - Using to count instead of
len().count() - Loading entire objects when you only need specific fields
- 遍历 objects 并访问 relations,却未使用 /
select_related()prefetch_related() - 使用 ,而不是
if queryset:.exists() - 使用 计数,而不是
len().count() - 只需要特定字段时,却加载整个 objects
Design Anti-Patterns
设计反模式
- Business logic in views instead of models
- Views performing calculations that belong in model methods
- Overusing signals for synchronous operations
- Creating new models when JSONField would suffice
- Forgetting to add indexes for filtered/sorted fields
- 将业务逻辑放在 views 中,而不是 models 中
- 在 views 中执行本应由 model 方法完成的计算
- 为同步操作滥用 signals
- 在 JSONField 足以满足需求时创建新 models
- 忘记为经过筛选或排序的字段添加索引
Integration
集成
Works with:
- pytest-django-patterns: Factory-based model testing
- celery-patterns: Async operations on models (pass IDs, not instances)
- django-forms: ModelForm validation and saving
兼容:
- pytest-django-patterns:基于 factory 的 model 测试
- celery-patterns:针对 models 的异步操作(传递 ID,而不是 instances)
- django-forms:ModelForm 验证和保存