在 Django 中链接多个 filter(),这是一个错误吗? [英] Chaining multiple filter() in Django, is this a bug?

查看:14
本文介绍了在 Django 中链接多个 filter(),这是一个错误吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直认为在 Django 中链接多个 filter() 调用总是与在单个调用中收集它们相同.

I always assumed that chaining multiple filter() calls in Django was always the same as collecting them in a single call.

# Equivalent
Model.objects.filter(foo=1).filter(bar=2)
Model.objects.filter(foo=1,bar=2)

但我在我的代码中遇到了一个复杂的查询集,但事实并非如此

but I have run across a complicated queryset in my code where this is not the case

class Inventory(models.Model):
    book = models.ForeignKey(Book)

class Profile(models.Model):
    user = models.OneToOneField(auth.models.User)
    vacation = models.BooleanField()
    country = models.CharField(max_length=30)

# Not Equivalent!
Book.objects.filter(inventory__user__profile__vacation=False).filter(inventory__user__profile__country='BR')
Book.objects.filter(inventory__user__profile__vacation=False, inventory__user__profile__country='BR')

生成的SQL是

SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") INNER JOIN "library_inventory" T5 ON ("library_book"."id" = T5."book_id") INNER JOIN "auth_user" T6 ON (T5."user_id" = T6."id") INNER JOIN "library_profile" T7 ON (T6."id" = T7."user_id") WHERE ("library_profile"."vacation" = False  AND T7."country" = BR )
SELECT "library_book"."id", "library_book"."asin", "library_book"."added", "library_book"."updated" FROM "library_book" INNER JOIN "library_inventory" ON ("library_book"."id" = "library_inventory"."book_id") INNER JOIN "auth_user" ON ("library_inventory"."user_id" = "auth_user"."id") INNER JOIN "library_profile" ON ("auth_user"."id" = "library_profile"."user_id") WHERE ("library_profile"."vacation" = False  AND "library_profile"."country" = BR )

具有链式 filter() 调用的第一个查询集两次连接 Inventory 模型,有效地在两个条件之间创建 OR,而第二个查询集将两个条件合并在一起.我期待第一个查询也会 AND 两个条件.这是预期的行为还是 Django 中的错误?

The first queryset with the chained filter() calls joins the Inventory model twice effectively creating an OR between the two conditions whereas the second queryset ANDs the two conditions together. I was expecting that the first query would also AND the two conditions. Is this the expected behavior or is this a bug in Django?

相关问题的答案是使用.filter().filter().filter()..."有一个缺点.在 Django 中? 似乎表明这两个查询集应该是等效的.

The answer to a related question Is there a downside to using ".filter().filter().filter()..." in Django? seems to indicated that the two querysets should be equivalent.

推荐答案

我的理解是它们在设计上略有不同(我当然愿意纠正):filter(A, B) 将首先根据 A 进行过滤,然后根据 B 进行子过滤,而 filter(A).filter(B) 将返回与 A 匹配的行和与 B 匹配的可能不同的行.

The way I understand it is that they are subtly different by design (and I am certainly open for correction): filter(A, B) will first filter according to A and then subfilter according to B, while filter(A).filter(B) will return a row that matches A 'and' a potentially different row that matches B.

看这里的例子:

https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

特别是:

同时应用单个 filter() 调用中的所有内容以过滤出符合所有这些要求的项目.连续的 filter() 调用进一步限制了对象集

Everything inside a single filter() call is applied simultaneously to filter out items matching all those requirements. Successive filter() calls further restrict the set of objects

...

在第二个示例 (filter(A).filter(B)) 中,第一个过滤器将查询集限制为 (A).第二个过滤器将博客集进一步限制为那些也是 (B) 的博客.第二个过滤器选择的条目可能与第一个过滤器中的条目相同也可能不同.`

In this second example (filter(A).filter(B)), the first filter restricted the queryset to (A). The second filter restricted the set of blogs further to those that are also (B). The entries select by the second filter may or may not be the same as the entries in the first filter.`

这篇关于在 Django 中链接多个 filter(),这是一个错误吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆