Запрос "AND" в Django: Обратный ForeignKey или ManyToMany дает неожиданный результат
Я обнаружил разные результаты по запросу "AND" в зависимости от того, был ли это обратный или прямой запрос.
В запросе 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))
Все они дают один и тот же результат: QuerySet, удовлетворяющий обоим условиям (x=1 и y=2).
Но если у меня есть запрос REVERSE FOREIGNKEY или MANY 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)
Допустим, у меня есть такие данные:
Headline | Pub Date Year | Authors | Blog |
---|---|---|---|
Pop 1 | 2023 | Juan | Pop |
Pop 2 | 2023 | Emma | Pop |
Pop 3 | 2010 | Juan, Walmer | Pop |
Other | 2023 | John | Beatles |
Я хочу сделать запрос "AND", чтобы получить авторов, которые удовлетворяют и заголовку, содержащему слово "Pop", и Pub Date Year, равному 2023.
Ожидаемый результат: Хуан и Эмма.
Headline | Pub Date Year | Authors | Blog |
---|---|---|---|
Pop 1 | 2023 | Juan | Pop |
Pop 2 | 2023 | Emma | Pop |
Мы можем использовать следующие методы:
- Многочисленные аргументы внутри фильтра.
Author.objects.filter(entry__headline__contains="Pop", entry__pub_date__year=2023)
- Q объект
Author.objects.filter(Q(entry__headline__contains="Pop") & Q(entry__pub_date__year=2023))
--> Эти два дают одинаковый ответ (ожидаемый результат: Хуан и Эмма) и создают один и тот же 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)
- ЗДЕСЬ ПРОБЛЕМА: С этим третьим вариантом результат другой. И я не понимаю почему.
Author.objects.filter(entry__headline__contains="Pop") & Author.objects.filter(entry__pub_date__year=2023)
Результат другой, запрос AND получает таких авторов: Хуан, Эмма, Хуан. Я подумал, что это также должно быть: Хуан и Эмма.
Но почему это не так?
Вот созданный 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)
>>>
ВОПРОСЫ:
- Почему третий вариант дает другой результат, чем два предыдущих?
- Является ли это ожидаемым результатом (Хуан, Эмма, Хуан?)