跨越 multi-valued 关系

Spanning multi-valued relationships

我阅读了 django 文档,发现了一些令人困惑的地方! https://docs.djangoproject.com/en/3.2/topics/db/queries/#spanning-multi-valued-relationships.

据说“当您根据 ManyToManyField 或反向外键过滤 object 时,您可能会对两种不同类型的过滤器感兴趣

“对于 select 所有包含标题中同时包含“Lennon”条目且发表于 2008 年的博客(满足这两个条件的同一条目),我们会写:”

Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)

“对于 select 所有标题中包含“Lennon”的条目以及 2008 年发布的条目的博客,我们会写:“

Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)

“假设只有一个博客的条目包含“Lennon”和 2008 年的条目,但是 2008 年的 none 条目包含“Lennon”。第一个查询不会 return 任何博客,但第二个查询会 return 那个博客

因此,通过阅读本指南,我脑海中产生了多个问题:

1- 这两种过滤有什么区别?我所知道的是,它们都必须 return 博客在标题中包含 'Lennon' 并且发表于 2008 年。我找不到重点。

2- 文档说此规则仅适用于 ManyToManyField 或反向外键。问题是,为什么?

What is the difference between these two types of filtering?

假设您有一个包含两个(或更多)条目的 Blog。其中一个条目的标题是一些包含单词 'Lennon' 不是 写于 2008 年的文本,此外该博客还有一个条目 without 标题中的单词 'Lennon',但写于 2008 年。

带有 .filter(entry__headline__contains='Lennon', entry__pub_date__year=2008) 的第一个查询查找标题中包含 'Lennon' 的条目 相同的条目应该写在 2008 年。对于我们在第一段中定义的样本数据,这将意味着此 Blog 未被选择 而不是 ,因为这两个条件适用于 same条目。

另一方面,如果您将其写为 .filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008),Django 将生成 两个 LEFT OUTER JOIN,这意味着它会查找一个博客,其中如果条目的标题包含 Lennon,并且一个条目(可以是 不同的 或相同的条目)是在 2008 年写的。这将检索 Blog定义在第一段。

The Document says this rule is just for ManyToManyField or a reverse ForeignKey. The question is, Why?

因为反向 ForeignKey 是 one-to-many 关系,而 ManyToManyField 跨越 many-to-many 关系。 …-to-many 在这里很重要。如果那将是 …-to-one,则根本不可能创建包含两个或更多条目的 Blog:如果 Blog 具有 ForeignKeyEntry model,那么就意味着博客只能有一个条目,不能有多个条目。由于这因此将条目数限制为一个,因此不可能有两个或更多条目,因此过滤将不会区分这两种情况。