如何使用反向外键或ManyToManyField执行Django“AND”查询?

问题描述 投票:0回答:1

我在“AND”查询上发现了不同的结果,具体取决于它是否是正向查询的反向。

  1. FORWARD 查询中,您可以执行以下操作:
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
Model.objects.filter(Q(x=1) & Q(y=2))

所有结果都相同:满足两个条件(x=1 和 y=2)的 QuerySet。

  1. 但是如果我有一个REVERSE FOREIGNKEYMANY TO MANY“AND”查询,则会发生不同的情况。

解释和代码示例。

我有这些型号:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

class Author(models.Model):
    name = models.CharField(max_length=100)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    authors = models.ManyToManyField(Author)

假设我有这些数据:

标题 发布日期年份 作者 博客
流行 1 2023 胡安 流行
流行2 2023 艾玛 流行
流行3 2010 胡安·沃尔默 流行
其他 2023 约翰 披头士乐队

我想进行“AND”查询来获取同时满足包含单词“Pop”的标题和发布日期年份等于 2023 年的作者。

预期结果:胡安和艾玛。

标题 发布日期年份 作者 博客
流行 1 2023 胡安 流行
流行2 2023 艾玛 流行

我们可以使用以下方法:

  1. 过滤器内有多个参数。
Author.objects.filter(entry__headline__contains="Pop", entry__pub_date__year=2023)
  1. Q 对象
Author.objects.filter(Q(entry__headline__contains="Pop") & Q(entry__pub_date__year=2023))

--> 这两个给出相同的答案(预期结果:Juan 和 Emma)并创建相同的 SQL:

SELECT  "blog_author"."id", "blog_author"."name", "blog_author"."email", "blog_author"."country_id" 

FROM "blog_author"

INNER JOIN "blog_entry_authors"

ON ("blog_author"."id" = "blog_entry_authors"."author_id")

INNER JOIN "blog_entry"

ON ("blog_entry_authors"."entry_id" = "blog_entry"."id")

WHERE ("blog_entry"."headline" LIKE %Pop% ESCAPE '\' AND "blog_entry"."pub_date" BETWEEN 2023-01-01 AND 2023-12-31)

问题来了

  1. 使用第三个选项,结果会有所不同。我也不明白为什么。
Author.objects.filter(entry__headline__contains="Pop") & Author.objects.filter(entry__pub_date__year=2023)

结果不同,AND查询得到这个作者:Juan,Emma,Juan。 我想这也应该是:胡安和艾玛。

但为什么不是呢?

这是创建的SQL(与前两个不同)

SELECT "blog_author"."id", "blog_author"."name", "blog_author"."email", "blog_author"."country_id" 

FROM "blog_author"

INNER JOIN "blog_entry_authors"

ON ("blog_author"."id" = "blog_entry_authors"."author_id")

INNER JOIN "blog_entry"

ON ("blog_entry_authors"."entry_id" = "blog_entry"."id")

LEFT OUTER JOIN "blog_entry_authors" T4

ON ("blog_author"."id" = T4."author_id")

LEFT OUTER JOIN "blog_entry" T5 ON (T4."entry_id" = T5."id")

WHERE ("blog_entry"."headline" LIKE %Pop% ESCAPE '\' AND T5."pub_date" BETWEEN 2023-01-01 AND 2023-12-31)
>>>

问题:

  1. 为什么第三个选项给出的结果与前两个选项不同?
  2. 这是预期的结果吗(Juan,Emma,Juan?)
django django-models django-queryset django-orm
1个回答
0
投票

解决了!!

StockOverflow 中的 @LearnerAndLearn 有一个很棒的答案解释了这种行为。

👉django 中多参数过滤器和链式过滤器的区别

© www.soinside.com 2019 - 2024. All rights reserved.