Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 基于多个关系存在性的Django查询集过滤 模型_Python_Django_Django Models_Django Queryset_Django Q - Fatal编程技术网

Python 基于多个关系存在性的Django查询集过滤 模型

Python 基于多个关系存在性的Django查询集过滤 模型,python,django,django-models,django-queryset,django-q,Python,Django,Django Models,Django Queryset,Django Q,这是我们的基本模型设置 一个列表有许多项,一个项可以在许多列表中。对于给定的项目,如果其任何列表良好(即list.bad==False),则该项目为良好。如果一个项目没有出现在任何好的列表中,那么它就是坏的 我们有一个针对项目的自定义查询集,其中有一个只返回好项目的方法,还有一个只返回坏项目的方法 类项(models.Model): objects=ItemQuerySet.as_manager() name=models.CharField(最大长度=255,唯一性=True) 类列表(mod

这是我们的基本模型设置

一个列表有许多项,一个项可以在许多列表中。对于给定的项目,如果其任何列表良好(即
list.bad==False
),则该项目为良好。如果一个项目没有出现在任何好的列表中,那么它就是坏的

我们有一个针对项目的自定义查询集,其中有一个只返回好项目的方法,还有一个只返回坏项目的方法

类项(models.Model):
objects=ItemQuerySet.as_manager()
name=models.CharField(最大长度=255,唯一性=True)
类列表(models.Model):
name=models.CharField(最大长度=255,唯一性=True)
bad=models.BooleanField(默认值=True)
items=models.ManyToManyField(Item,related_name='lists')
类ItemQuerySet(models.QuerySet):
def坏(自身):
返回self.exclude(lists\uu bad=False)
def良好(自我):
返回self.filter(lists\uu bad=False)
情景 下面是一个我们遇到问题的场景示例:一个坏列表、一个好列表和两个项目

BadList:GoodList:
-项目1-项目1
-项目2
由于Item1至少出现在一个良好列表中,因此它应该出现在
Item.objects.good()
中,而不是
Item.objects.bad()

由于Item2没有出现在任何好的列表中,它应该出现在
Item.objects.bad()
中,而不是
Item.objects.good()

我们可以这样设置场景:

#创建两个列表。
>>>goodlist=List.objects.create(name='goodlist',bad=False)
>>>badlist=List.objects.create(name='badlist',bad=True)
#创建两个项目。
>>>item1=Item.objects.create(name='item1')
>>>item2=Item.objects.create(name='item2')
#两个列表中都有项目1
>>>goodlist.items.add(item1)
>>>badlist.items.add(item1)
#项目2仅在坏名单中
>>>badlist.items.add(item2)
事实上,
Item.objects.good()
Item.objects.bad()
的工作方式与我们预期的一样:

>>Item.objects.bad()#这会返回我们想要的!好!!
>>>Item.objects.good()#这将返回我们想要的!好!!
问题 谢谢你容忍我。这就是我们的自定义查询集出错的地方。如果我们通过单个列表的项访问
good()
bad()
自定义查询集方法,我们会得到不正确的结果

>>> badlist.items.bad() # WRONG! We want to ONLY see item2 here!
<QuerySet [<Item: item1>, <Item: item2>]

>>> badlist.items.good() # WRONG! We want to see item1 here!
<QuerySet []>
>>badlist.items.bad()#错误!我们只想在这里看到项目2!
>>坏名单。物品。好()#错!我们想在这里看到项目1!
看起来,当我们执行
badlist.items.bad()
时,查询只考虑
badlist
来确定项目是否是坏的,而不考虑项目所在的所有列表。但我不明白为什么会这样

我的想法是,在
ItemQuerySet.bad
方法中,我想要类似于
self.exclude(any\u lists\u bad=False)
的东西,而不仅仅是
self.exclude(lists\u bad=False)
。但是当然,
any__
关键字实际上并不存在,我不知道如何在Django查询集中正确地表达这种逻辑。似乎使用
Q
对象可能是前进的方向,但我仍然不太确定如何用
Q
对象表达这样的查询

在我们的实际数据库中,只有不到100个列表,但有数百万个条目。因此,出于性能原因,最好只使用一个查询,而不是一个属性或多个查询


干杯

如果您打印出由
badlist.items.bad()
生成的查询,您将看到问题:它将在through表上使用
WHERE
子句,从而将列表仅限于badlist。如果要正确应用
坏的
好的
,则需要从
项目
级别开始,然后按列表中的项目进行筛选

item_ids = list(badlist.items.values_list('id'), flat=True)

Item.objects.bad().filter(id__in=item_ids)

Item.objects.good().filter(id__in=item_ids)
编辑:我无法在没有模式的情况下进行测试,但我认为您可以使用注释统计列表的数量,然后通过它进行过滤

def annotate_good(self);
    return self.annotate(good=Count(Case(When(lists__bad=False, then=1), default=0)))

def good(self):
    return self.annotate_good().exclude(good=0)

def bad(self):
    return self.annotate_good().filter(good=0)

否则,如果性能确实是一个问题,我会在项目模型中添加一个好的或坏的字段,并在保存时进行更新,以便查询变得非常简单。

谢谢您的回答!这确实可以正常工作,但是我担心其他使用代码的人会尝试使用
badlist.items.good()
路径,而不知道更好的方法。我想避免让人们像那样被误导。此外,我想在原始帖子中提到这一点:在我们的实际数据库中,只有不到100个列表,但有数百万个条目。因此,出于性能原因,最好只使用一个查询,而不是一个属性或多个查询。我认为您可以使用queryset注释来实现这一点。我用一个我认为可行的解决方案编辑了上面的答案。否则,为了提高性能,我只需将bad/good列添加到Item并进行更新,这使得查询更加简单