You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 18:09:02