查询集中相关多对多字段的具体加载

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 相关实例,并且两个是NULLs,那么该项目将在查询集中出现两次。如果一个对象有no abs,或者例如一个非NULL,那么它将不在查询集中。 @super_sk:您希望B 实例至少 有一个NULL 日期,还是只有 NULL-日期?对于没有 AB 实例的 Bs 怎么办? 我想要所有 B 实例,无论它们拥有多少 ab。但是,没有abNON-NULL 日期必须出现在检索到的每个B 的集合中。抱歉,似乎不清楚:( . 例如,[b1, b2]b1.ab_set = [b1ab1 (null date), b1ab2 (date)]b2.ab_set = [b2ab1 (date), b2ab2 (date)]。预期结果为b1b2,分别为b1ab1empty_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,我认为它对我的情况没有那么有用。

【讨论】:

以上是关于查询集中相关多对多字段的具体加载的主要内容,如果未能解决你的问题,请参考以下文章

在表单集中访问多对多“通过”关系字段

多对多计数大于的 Doctrine 查询生成器

Django如何过滤多对多字段中的对象,而不是原始查询集

查询多对多字段

如何过滤多对多字段的模型?

Django ORM 查询更新反向多对多字段