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

Django中通过中间表使用Prefetch并添加过滤条件的问题

Django多对多关联查询问题:预取活跃成员时出现重复表连接

模型定义

class Person(models.Model):
    name = models.CharField(max_length=255)

class Group(models.Model):
    name = models.CharField(max_length=255)
    members = models.ManyToManyField(Person, through="Membership")

class Membership(models.Model):
    group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="membership")
    person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="membership")
    is_active = models.BooleanField(null=True, blank=True)

Membership模型中的is_active字段表示用户是否仍为群组成员。

尝试的查询代码

想要查询群组并预取所有活跃成员,使用了以下代码:

from sample.models import Person, Group
from django.db.models import Prefetch
from django.db import connection, reset_queries
reset_queries()
qs = Group.objects.prefetch_related(
    Prefetch(
        "members", queryset=Person.objects.filter(membership__is_active=True),
    )
)
print(list(qs.all()))
print(len(connection.queries)) # 预期应该是2次查询

问题:生成的SQL出现重复表连接

生成的预取SQL中,sample_membership表被连接了两次,且只有一个应用了is_active过滤:

SELECT 
  ("sample_membership"."group_id") AS "_prefetch_related_val_group_id", 
  "sample_person"."id", 
  "sample_person"."name" 
FROM 
  "sample_person" INNER JOIN "sample_membership" ON ( "sample_person"."id" = "sample_membership"."person_id")
  INNER JOIN "sample_membership" T3 ON ( "sample_person"."id" = T3."person_id") 
WHERE "sample_membership"."is_active" AND T3."group_id" IN (1, 2)

补充:序列化器代码

serializers.py文件内容:

from rest_framework import serializers
from .models import Person, Group
class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = '__all__'

class GroupSerializer(serializers.ModelSerializer):
    members = PersonSerializer(many=True)
    class Meta:
        model = Group
        fields = '__all__'

希望在GroupSerializer的输出中仅包含拥有活跃Membership的成员,测试代码如下:

from sample.models import Person, Group, Membership
from sample.serializers import GroupSerializer
from django.db.models import Prefetch
from django.db import connection, reset_queries
reset_queries()
qs = Group.objects.prefetch_related(
    Prefetch(
        "membership",
      queryset=Membership.objects.filter(is_active=True).select_related("person"),
    )
)
for q in list(qs.all()):
    gs = GroupSerializer()
    gs.to_representation(instance=q)

内容的提问来源于stack exchange,提问作者willowherb

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:28:22