django - 相关模型领域的Django filter()

标签 django django-models django-queryset

我想我缺少关于Django的filter()方法应该如何工作的非常基本和根本的东西。

使用以下模型:

class Collection(models.Model): 
    pass

class Item(models.Model):
    flag = models.BooleanField()
    collection =  models.ForeignKey(Collection)


并通过在问题底部调用populate()函数提供数据,请尝试在./manage.py shell中执行以下命令:

len(Collection.objects.filter(item__flag=True))


我的期望是,它将打印“ 2”,这是具有至少一个带有flag = True的项的集合的数量。此期望基于https://docs.djangoproject.com/en/1.5/topics/db/queries/#lookups-that-span-relationships上的文档,该文档的示例为“此示例检索名称为'Beatles Blog'的Blog的所有Entry对象”。

但是,上面的调用实际上会打印“ 6”,这是具有flag = True的Item记录的数量。但是,返回的实际对象是Collection对象。似乎它多次返回同一个Collection对象,对于每个带有flag = True的对应Item记录一次。可以通过以下方式确认:

queryset = Collection.objects.filter(item__flag=True)
queryset[0] == queryset[1]


打印真。

这是正确的行为吗?如果是这样,理由是什么?如果期望如此,则可以将文档解释为严格正确,但是忽略了每个对象可以多次返回的说法。

这是一个相关的示例,它的行为似乎非常令人惊讶(或完全是错误的)。在自定义模型管理器添加了exclude()调用,然后调用者随后添加filter()的情况下,我陷入了困境:

from django.db.models import Count    
[coll.count for coll in Collection.objects.filter(item__flag=True).annotate(count=Count("item"))]
[coll.count for coll in Collection.objects.exclude(item=None).filter(item__flag=True).annotate(count=Count("item"))]


第一种情况打印“ [2,4]”,而第二种情况打印“ [8,16]” !!!

填充功能:

def populate():
    Collection.objects.all().delete()

    collection = Collection()
    collection.save()
    item = Item(collection=collection, flag=True)
    item.save()
    item = Item(collection=collection, flag=True)
    item.save()
    item = Item(collection=collection, flag=False)
    item.save()
    item = Item(collection=collection, flag=False)
    item.save()

    collection = Collection()
    collection.save()
    item = Item(collection=collection, flag=True)
    item.save()
    item = Item(collection=collection, flag=True)
    item.save()
    item = Item(collection=collection, flag=True)
    item.save()
    item = Item(collection=collection, flag=True)
    item.save()

    collection = Collection()
    collection.save()
    item = Item(collection=collection, flag=False)
    item.save()
    item = Item(collection=collection, flag=False)
    item.save()
    item = Item(collection=collection, flag=False)
    item.save()
    item = Item(collection=collection, flag=False)
    item.save()

最佳答案

事实证明,这包括两个部分。首先是distinct()方法,文档对此说:


默认情况下,QuerySet不会消除重复的行。在实践中,
这很少有问题,因为诸如
Blog.objects.all()不会引入重复结果的可能性
行。但是,如果您的查询跨越多个表,则可以
评估QuerySet时得到重复的结果。那是当你
使用distinct()。


预期输出以下“ 2”:

len(Collection.objects.filter(item__flag=True).distinct())


但是,这对于使用annotate()给出的更复杂的示例没有帮助。事实证明,这是一个已知问题的实例:https://code.djangoproject.com/ticket/10060

关于django - 相关模型领域的Django filter(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17132450/

相关文章:

python - 如何布局队列/ worker 结构以支持多种环境的大型任务?

Django:order_by多个字段

django - 如何在 Django 表单中将标签设置为粗体?

django - 通过 django shell 保存图像/文件

python - Django Form 拒绝在多个选择字段中呈现查询集

Django:检索对象的最佳方式

django - AttributeError : type object 'User' has no attribute 'name'

Django:创建多项选择字段的最佳方式

python - Django 查询集和 GROUP BY

python - 从URL上传Django ImageField