Django带through中间表的多对多关系如何避免大量冗余查询
问题原因
你之前的prefetch_related()没有传入需要预取的关联字段,相当于没有开启预取逻辑。同时因为你的序列化器使用membership_set作为成员字段的数据源,且每个Membership还需要关联查询User对象,需要两层预取才能覆盖所有关联查询。
优化后的查询写法
只需要在prefetch_related中指定需要预取的两层关联路径即可,总共只会触发3次查询(战役+owner查询、批量Membership查询、批量User查询),无论有多少战役和成员都不会产生额外查询:
campaigns = user.campaigns.select_related('owner').prefetch_related('membership_set__user')
如果需要更灵活的预取控制(比如对成员列表做过滤、排序),可以使用Prefetch对象自定义预取的查询集:
from django.db.models import Prefetch # 自定义预取的Membership查询集,同时预取关联的user membership_queryset = Membership.objects.select_related('user').order_by('-is_dm') campaigns = user.campaigns.select_related('owner').prefetch_related( Prefetch('membership_set', queryset=membership_queryset) )
注意:你的序列化器中成员字段的
source指定为membership_set,所以预取时必须使用membership_set作为关联路径的开头,如果使用members(多对多字段名)的话预取结果无法被序列化器复用,仍然会触发额外查询。
效果验证
调整后访问成员信息不会触发额外查询:
# 不会产生新的数据库查询 print(campaigns[0].membership_set.all()[0].user.name)
内容的提问来源于stack exchange,提问作者Kevin Renskers
相关产品推荐
相关产品推荐

