Django多对多关联模型单步过滤查询方法咨询
单步Django查询实现指定用户关联账户的全量所有者记录获取
模型定义
class Person(models.Model): name = models.CharField(max_length=255) class BankAccount(models.Model): iban = models.CharField(max_length=28) owners = models.ManyToManyField(Person, through='BankAccountPerson') class BankAccountPerson(models.Model): bank_account = models.ForeignKey(BankAccount, on_delete=models.RESTRICT, related_name = 'ownership') person = models.ForeignKey(Person, on_delete=models.RESTRICT, related_name = 'ownership') is_owner = models.BooleanField(null=True, blank=True) class Meta: unique_together= [['bank_account','person']]
问题场景
假设账户1关联两个所有者:person:1和person:2。执行以下查询时:
person=Person.objects.get(pk=1) collection = BankAccount.objects.filter(owners=person)
仅能得到关联person:1的单条记录,但实际需要获取该账户的所有两条所有者记录(person:1和person:2),即筛选出包含指定用户作为所有者之一的账户的全量关联信息。
已有解决方案
1. 原生SQL实现
SELECT * FROM structure_bankaccount INNER JOIN "structure_bankaccountperson" ON ("structure_bankaccount"."id" = "structure_bankaccountperson"."bank_account_id") WHERE structure_bankaccount.id in (SELECT bank_account_id FROM "structure_bankaccountperson" WHERE "structure_bankaccountperson"."person_id" = 1)
2. 两步Django查询实现
owned_accounts = BankAccountPerson.objects.filter(person=person).values_list('bank_account_id') collection = BankAccount.objects.filter(id__in=owned_accounts)
核心疑问
能否通过Q对象、F对象或其他Django查询函数,用单步过滤查询实现该需求?
单步查询实现方案
方案一:使用Exists子查询
利用Django的Exists和OuterRef构造子查询,一步筛选出目标账户并预加载所有所有者记录:
from django.db.models import Exists, OuterRef person = Person.objects.get(pk=1) collection = BankAccount.objects.filter( Exists( BankAccountPerson.objects.filter( bank_account=OuterRef('pk'), person=person ) ) ).prefetch_related('ownership')
Exists子查询负责筛选出包含指定用户的账户prefetch_related('ownership')一次性加载该账户的所有关联所有者记录,避免N+1查询问题
方案二:反向关联过滤+去重
通过关联模型的反向关系直接筛选,配合distinct()避免重复账户:
person = Person.objects.get(pk=1) collection = BankAccount.objects.filter( ownership__person=person ).prefetch_related('ownership').distinct()
ownership__person=person通过关联模型筛选出指定用户关联的账户distinct()确保每个账户只返回一次prefetch_related('ownership')加载该账户的全量所有者记录
内容的提问来源于stack exchange,提问作者Tomasz Brzezina
相关产品推荐
相关产品推荐

