Распространение многозначных отношений

Я читал документацию django и нашел кое-что непонятное! https://docs.djangoproject.com/en/3.2/topics/db/queries/#spanning-multi-valued-relationships.

Утверждается, что "Когда вы фильтруете объект на основе поля ManyToManyField или обратного ForeignKey, существует два различных вида фильтра, которые могут вас заинтересовать"

"Чтобы выбрать все блоги, содержащие записи с "Ленноном" в заголовке и опубликованные в 2008 году (одна и та же запись удовлетворяет обоим условиям), мы напишем: "

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

"Чтобы выбрать все блоги, которые содержат запись с "Ленноном" в заголовке, а также запись, которая была опубликована в 2008 году, мы напишем: "

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

"Предположим, что существует только один блог, в котором есть записи, содержащие слово "Леннон", и записи 2008 года, но ни одна из записей 2008 года не содержит слова "Леннон". Первый запрос не вернет ни одного блога, но второй запрос вернет этот единственный блог"

Итак, прочитав это руководство, у меня в голове возникло несколько вопросов:

1- В чем разница между этими двумя типами фильтрации? Я знаю, что оба они должны возвращать блоги, которые содержат 'Lennon' в заголовке и были опубликованы в 2008 году. Я не могу найти суть.

2- Документ говорит, что это правило только для ManyToManyField или обратного ForeignKey. Вопрос в том, почему?

В чем разница между этими двумя типами фильтрации?

Представьте себе, что у вас есть блог Blog с двумя (или более) записями. Одна из записей имеет в качестве заголовка текст, содержащий слово 'Lennon', но не написанный в 2008 году, кроме того, в блоге есть запись без слова 'Lennon' в заголовке, но написанная в 2008 году.

Первый запрос с .filter(entry__headline__contains='Lennon', entry__pub_date__year=2008) ищет запись, которая содержит 'Lennon' в заголовке и эта же запись должна быть написана в 2008 году. Для наших выборочных данных, определенных в первом параграфе, это означает, что эта Blog будет не выбрана, поскольку два условия применяются к одной и той же записи.

Если с другой стороны вы напишите это как .filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008), Django сделает два LEFT OUTER JOIN, это означает, что он ищет блог, в котором одна из записей имеет заголовок, содержащий Lennon, и запись (это может быть разная или та же самая запись) была написана в 2008 году. Таким образом, будет получено Blog, определенное в первом параграфе.

Документ говорит, что это правило только для ManyToManyField или обратного ForeignKey. Вопрос в том, почему?

Потому что обратное отношение ForeignKey является отношением один-ко-многим, а ManyToManyField охватывает отношение многие-ко-многим. Здесь важно …-to-many. Если это будет …-to-one, то просто невозможно сделать Blog с двумя или более записями: если Blog имеет ForeignKey к модели Entry, то это означает, что блог может иметь только одну запись, а не несколько. Поскольку таким образом количество записей ограничивается одной, невозможно иметь две или более записей, и поэтому фильтрация не будет различать эти два случая.

Вернуться на верх