Django跨1:N、N:1关联关系的QuerySet高效查询方案咨询
Django 跨多层外键关联查询最优方案
首先基于你给出的关联关系,先做模型定义假设(如果你的外键字段命名不同,替换对应字段名即可):
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) # 其他自定义字段 class Entrie(models.Model): title = models.CharField(max_length=200) # Entrie表外键关联Blog blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name="entries") # 其他自定义字段 class Collection(models.Model): name = models.CharField(max_length=100) # Collection表外键关联Entrie entrie = models.ForeignKey(Entrie, on_delete=models.CASCADE, related_name="collections") # 其他自定义字段
1. 直接跨关联查询(无需手动处理中间表)
Django ORM原生支持双下划线__跨多层外键关联查询,不需要先查中间表Entrie再拼接结果,直接从Collection出发即可查询、过滤关联的Blog字段:
- 示例:筛选关联Blog名称为「技术笔记」的所有Collection
target_collections = Collection.objects.filter(entrie__blog__name="技术笔记")
- 示例:获取单条Collection对应的Blog实例
collection = Collection.objects.get(id=xxx) related_blog = collection.entrie.blog
2. 性能优化:避免N+1查询问题
如果需要批量查询Collection并获取对应Blog信息,普通写法会触发N+1查询:查询1次Collection列表,遍历每一条Collection时各查询1次Entrie、1次Blog,总查询次数为1 + 2*N。
使用select_related可以在单次SQL查询中通过JOIN直接拉取关联的Entrie、Blog数据,后续遍历不会触发额外查询:
# 预加载关联的Entrie和Blog所有字段 collections = Collection.objects.select_related("entrie", "entrie__blog").all() # 遍历获取Blog信息无额外查询 for col in collections: print(f"Collection:{col.name} 关联Blog:{col.entrie.blog.name}")
如果只需要Blog的部分字段,可以搭配only进一步减少查询字段,提升性能:
collections = Collection.objects.select_related("entrie", "entrie__blog").only("name", "entrie__title", "entrie__blog__name")
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

