查询集中相关多对多字段的具体加载
Posted
技术标签:
【中文标题】查询集中相关多对多字段的具体加载【英文标题】:Specific loading of related manytomany field in queryset 【发布时间】:2018-11-16 06:41:03 【问题描述】:我在这样的多对多关系中使用带有额外字段的中间模型:
class A(models.Model):
name = models.CharField(max_length=128)
class B(models.Model):
name = models.CharField(max_length=128)
a = models.ManyToManyField(A, through='AB')
class AB(models.Model):
a = models.ForeignKey(A, on_delete=models.CASCADE)
b = models.ForeignKey(B, on_delete=models.CASCADE)
number = models.IntegerField(default=0)
date = models.DateTimeField()
默认情况下,AB.date
在数据库中为 NULL。
我用类似B.objects.all()
的东西检索我所有的B
实例。
然后,对于B
的每个实例,我可以得到一组AB
像这样b_instance.ab_set.all()
。
如何仅加载date
为空的ab_set
元素?
在 SQL 中它看起来像这样:
SELECT * FROM B
INNER JOIN AB ON AB.id = B.ab_id AND AB.date IS NULL
【问题讨论】:
【参考方案1】:您可以使用__isnull
[doc] 字段查找执行过滤器,例如:
b_instance.ab_set.filter(<b>date__isnull=True</b>)
所以我们在集合上.filter(..)
,通过指定date
字段isnull
。
或者,如果您还想使用非None
date
进行查询,您可以使用date=None
进行过滤:
b_instance.ab_set.filter(<b>date=None</b>)
【讨论】:
我看到了__isnull
field lookup。在我的示例中,我想在使用B.objects.all()
时自动对B
应用过滤器。这样的事情不起作用:B.objects.filter(ab__date__isnull=True)
.
但是B.objects.filter(..)
返回一个B
对象列表(有些项目出现多次)per ab
具有NULL
-date 的关系。因此,如果一个B
元素具有三个ab
相关实例,并且两个是NULL
s,那么该项目将在查询集中出现两次。如果一个对象有no ab
s,或者例如一个非NULL
,那么它将不在查询集中。
@super_sk:您希望B
实例至少 有一个NULL
日期,还是只有 NULL
-日期?对于没有 AB
实例的 B
s 怎么办?
我想要所有 B
实例,无论它们拥有多少 ab
。但是,没有ab
和NON-NULL
日期必须出现在检索到的每个B
的集合中。抱歉,似乎不清楚:( .
例如,[b1, b2]
和 b1.ab_set = [b1ab1 (null date), b1ab2 (date)]
和 b2.ab_set = [b2ab1 (date), b2ab2 (date)]
。预期结果为b1
和b2
,分别为b1ab1
和empty_set
。【参考方案2】:
通过对我的问题的一些研究,我终于找到了可以解决问题的东西。
我使用Model method
过滤我的对象集:
class B(models.Model):
...
def get_ab_with_null_date(self):
return self.ab_set.filter(date__isnull=True)
所以,我可以像这样在我的模板中过滤ab_set
:
% for b in list_of_B %
% for ab in b.get_ab_with_null_date %
...
% endfor %
% endfor %
您认为有更有效的方法来执行此操作吗?
另外,我看到了一些关于覆盖Manager 像这样:
b = B.objects.get(...)
b.custom_manager.get_ab_with_null_date() # return filtered ab_set with null date
由于我没有直接在视图中操作我的ab_set
,我认为它对我的情况没有那么有用。
【讨论】:
以上是关于查询集中相关多对多字段的具体加载的主要内容,如果未能解决你的问题,请参考以下文章