flowchart TD
A["创建 QuerySet"] --> B{"是否有过滤/排序操作?"}
B -->|是| C["链式操作创建新 QuerySet"]
B -->|否| D["QuerySet 对象准备完成"]
C --> D
D --> E{"是否触发求值操作?"}
E -->|否| F["保持惰性状态<br/>_result_cache = None"]
E -->|是| G["检查 _result_cache"]
G --> H{"缓存是否为空?"}
H -->|否| I["直接返回缓存结果"]
H -->|是| J["执行 _fetch_all"]
J --> K["创建 SQL 编译器"]
K --> L["执行数据库查询"]
L --> M["创建模型实例"]
M --> N["处理关联对象"]
N --> O["存储到 _result_cache"]
O --> P["返回结果"]
F --> E
style A fill:#e1f5fe
style F fill:#fff3e0
style P fill:#e8f5e8
style L fill:#ffebee
flowchart LR
A["User.objects"] --> B[".filter age__gt=18"]
B --> C["新 QuerySet 1<br/>仍然惰性"]
C --> D[".filter name__startswith='A'"]
D --> E["新 QuerySet 2<br/>仍然惰性"]
E --> F[".order_by 'id'"]
F --> G["新 QuerySet 3<br/>仍然惰性"]
G --> H["触发求值操作<br/>如 list, len, for循环"]
H --> I["执行数据库查询"]
style A fill:#e3f2fd
style C fill:#fff3e0
style E fill:#fff3e0
style G fill:#fff3e0
style I fill:#ffebee
flowchart TD
A["QuerySet 对象<br/>_result_cache = None"] --> B{"触发方式"}
B -->|迭代| C["for item in qs:<br/>__iter__"]
B -->|长度| D["len qs<br/>__len__"]
B -->|布尔值| E["if qs:<br/>__bool__"]
B -->|索引访问| F["qs[0]<br/>__getitem__"]
B -->|列表转换| G["list qs"]
B -->|计数| H["qs.count"]
B -->|存在性检查| I["qs.exists"]
C --> J["调用 _fetch_all"]
D --> J
E --> J
F --> K{"是否有缓存?"}
G --> J
H --> L["直接执行 COUNT 查询"]
I --> M["执行 EXISTS 查询"]
K -->|有| N["直接返回缓存结果"]
K -->|无| O["创建限制查询"]
J --> P["执行完整查询<br/>填充 _result_cache"]
O --> Q["执行单条/切片查询"]
style A fill:#e1f5fe
style J fill:#fff3e0
style P fill:#e8f5e8
style L fill:#e8f5e8
style M fill:#e8f5e8
# 逐行处理结果,创建模型实例 for row in compiler.results_iter(results): obj = model_cls.from_db(db, init_list, row[model_fields_start:model_fields_end])
# 处理关联对象 if related_populators: for rel_populator in related_populators: rel_populator.populate(row, obj)
# 处理注解字段 if annotation_col_map: for attr_name, col_pos in annotation_col_map.items(): setattr(obj, attr_name, row[col_pos])
# 处理已知的关联对象 if queryset._known_related_objects: for field, rel_objs in queryset._known_related_objects.items(): ifhasattr(obj, field.get_cache_name()): continue pk = getattr(obj, field.get_attname()) try: rel_obj = rel_objs[pk] except KeyError: pass else: setattr(obj, field.name, rel_obj)
yield obj # 🔑 生成器模式,逐个返回对象
关键特性:
使用生成器模式,内存效率高
支持分块获取数据(chunked_fetch)
自动处理关联对象和注解字段
4. 流程图详解
4.1 QuerySet 状态变化
stateDiagram-v2
[*] --> Created: "创建 QuerySet"
Created --> Filtered: "添加过滤条件"
Filtered --> Filtered: "链式操作"
Filtered --> Evaluated: "触发求值"
Created --> Evaluated: "直接求值"
Evaluated --> Cached: "结果已缓存"
Cached --> Cached: "重复访问缓存"
note right of Created
"_result_cache = None<br/>query 对象已创建"
end note
note right of Filtered
"仍然 _result_cache = None<br/>query 对象被修改"
end note
note right of Evaluated
"执行数据库查询<br/>_fetch_all 被调用"
end note
note right of Cached
"_result_cache 包含结果<br/>后续访问无需查询数据库"
end note
4.2 内存使用优化策略
flowchart TD
A["大量数据查询"] --> B{"选择迭代方式"}
B -->|"使用 QuerySet 直接迭代"| C["list qs<br/>加载所有数据到内存"]
B -->|"使用 iterator"| D["qs.iterator<br/>逐条获取,低内存占用"]
B -->|"使用 批量处理"| E["分批处理<br/>batch_size 参数"]
C --> F["高内存使用<br/>适合小数据集"]
D --> G["低内存使用<br/>适合大数据集<br/>但不能重复迭代"]
E --> H["平衡内存和性能<br/>可控制批次大小"]
style C fill:#ffebee
style D fill:#e8f5e8
style E fill:#fff3e0
5. 性能优化机制
5.1 select_related 优化
flowchart TD
A["QuerySet.select_related 'foreign_key'"] --> B["修改 SQL 查询添加 JOIN"]
B --> C["执行单次数据库查询"]
C --> D["获取包含关联数据的结果行"]
D --> E["创建主模型实例"]
E --> F["RelatedPopulator.populate"]
F --> G["从同一行数据创建关联对象"]
G --> H["设置对象间的关联关系"]
H --> I["避免额外的数据库查询"]
J["不使用 select_related"] --> K["创建主模型实例"]
K --> L["访问关联属性时"]
L --> M["触发额外的数据库查询"]
M --> N["N+1 查询问题"]
style A fill:#e8f5e8
style I fill:#e8f5e8
style N fill:#ffebee
all_lookups = deque(related_lookups) while all_lookups: lookup = all_lookups.popleft() if lookup.prefetch_to in done_queries: if lookup.queryset: raise ValueError("'%s' lookup was already seen with a different queryset. " "You may need to adjust the ordering of your lookups." % lookup.prefetch_to) continue
defoptimization_examples(): # ❌ N+1 查询问题 posts = Post.objects.all() for post in posts: print(f"{post.title} by {post.author.name}") # 每次都查询数据库
# ✅ 使用 select_related 优化 实现原理就是把user和book进行inner join了 posts = Post.objects.select_related('author').all() for post in posts: print(f"{post.title} by {post.author.name}") # 只查询一次数据库
# ✅ 大数据集的内存优化 # 方式1:使用 iterator,低内存占用 for user in User.objects.all().iterator(): process_user(user)
# 方式2:分批处理 batch_size = 1000 for user in User.objects.all().iterator(chunk_size=batch_size): process_user(user)