我正在使用具有多对多关系的额外字段的中间模型,如下所示:
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
检索我所有的B.objects.all()
实例。
然后,对于B
的每个实例,我可以得到一组像这样的AB
,b_instance.ab_set.all()
。
如何只加载ab_set
为空的date
元素?
在SQL中,它看起来像这样:
SELECT * FROM B
INNER JOIN AB ON AB.id = B.ab_id AND AB.date IS NULL
您可以使用__isnull
[doc]字段查找执行过滤器,例如:
b_instance.ab_set.filter(date__isnull=True)
因此我们通过指定.filter(..)
字段date
来设置isnull
。
或者,如果您想要使用非None
date
进行查询,则可以使用date=None
进行过滤:
b_instance.ab_set.filter(date=None)
通过对我的问题的一些研究,我终于找到了可以解决问题的东西。
我使用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
,我认为这对我的情况不太有用。