В чем разница между фильтром с несколькими аргументами и цепным фильтром в django?
python
django
django-models
тестмобиль
источник
источник
Ответы:
Как вы можете видеть в сгенерированных операторах SQL, разница не в «ИЛИ», как некоторые могут подумать. Так размещаются WHERE и JOIN.
Пример1 (та же объединенная таблица): из https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Blog.objects.filter( entry__headline__contains='Lennon', entry__pub_date__year=2008)
Это даст вам все блоги, в которых есть одна запись с обоими
(entry__headline__contains='Lennon') AND (entry__pub_date__year=2008)
, чего и следовало ожидать от этого запроса.Результат:
Blog with {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
Пример 2 (связанный)
Blog.objects.filter( entry__headline__contains='Lennon' ).filter( entry__pub_date__year=2008)
Это будет охватывать все результаты из примера 1, но даст немного больший результат. Потому что он сначала фильтрует все блоги,
(entry__headline__contains='Lennon')
а затем фильтрует результаты(entry__pub_date__year=2008)
.Разница в том, что он также даст такие результаты, как:
Один блог с несколькими записями
{entry.headline: '**Lennon**', entry.pub_date: 2000}, {entry.headline: 'Bill', entry.pub_date: **2008**}
Когда был оценен первый фильтр, книга включается из-за первой записи (даже если в ней есть другие записи, которые не совпадают). При оценке второго фильтра книга включается из-за второй записи.
Одна таблица: Но если запрос не включает объединенные таблицы, как в примере от Yuji и DTing. Результат такой же.
источник
(entry__headline__contains='Lennon')
а затем фильтры результатов(entry__pub_date__year=2008)
» «Если« то из результата »верно, то почему оно будет включать что-то сentry.headline == 'Bill'
.. .не удалосьentry__headline__contains='Lennon'
отфильтроватьBill
экземпляр?Случай, в котором результаты «запрос-фильтр с несколькими аргументами» отличается от «запрос-фильтр-цепочки», следующий:
Пример:
Считайте, что в моем приложении
my_company
есть две моделиEmployee
иDependent
. У сотрудникаmy_company
может быть больше, чем иждивенцев (другими словами, иждивенец может быть сыном / дочерью одного сотрудника, в то время как у сотрудника может быть более одного сына / дочери).Эхх, при условии, что как муж и жена, оба не могут работать в a
my_company
. Я взял пример 1: мИтак,
Employee
это ссылочная модель, на которую может ссылаться больше, чемDependent
ссылочная модель. Теперь рассмотрим состояние отношения следующим образом:Теперь мой запрос:
Найти всех сотрудников, у которых сын / дочь имеют отличительные знаки (скажем,> = 75%) как в колледже, так и в школе?
>>> Employee.objects.filter(dependent__school_mark__gte=75, ... dependent__college_mark__gte=75) [<Employee: A>]
Результат «А» зависит от «А1» имеет отличительные знаки как в колледже, так и в школе зависит от сотрудника «А». Примечание «B» не выбрано, потому что ни один из детей «B» не имеет отличительных оценок как в колледже, так и в школе. Реляционная алгебра:
Во-вторых, мне нужен запрос:
Найти всех сотрудников, некоторые из иждивенцев которых имеют отличия в колледже и школе?
>>> Employee.objects.filter( ... dependent__school_mark__gte=75 ... ).filter( ... dependent__college_mark__gte=75) [<Employee: A>, <Employee: B>]
На этот раз «B» также выбрана, потому что у «B» двое детей (более одного!), Один имеет отличительный знак в школе «b1», а другой имеет отличительный знак в колледже «b2».
Порядок фильтрации не имеет значения, мы также можем написать запрос выше как:
>>> Employee.objects.filter( ... dependent__college_mark__gte=75 ... ).filter( ... dependent__school_mark__gte=75) [<Employee: A>, <Employee: B>]
результат такой же! Реляционная алгебра может быть:
Обратите внимание на следующее:
dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75) dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75)
Выводит тот же результат:
[<Dependent: a1>]
Я проверяю целевой SQL-запрос, созданный Django, используя
print qd1.query
иprint qd2.query
оба они одинаковы (Django 1.6).Но семантически оба для меня разные . первый выглядит как простой раздел σ [school_mark> = 75 AND college_mark> = 75] (Dependent), а второй - как медленный вложенный запрос: σ [school_mark> = 75] (σ [College_mark> = 75] (Dependent)).
Если нужен код @codepad
Кстати, это приведено в документации @ Spanning многозначных отношений. Я только что добавил пример, думаю, это будет полезно для кого-то нового.
источник
В большинстве случаев для запроса существует только один возможный набор результатов.
Использование цепочки фильтров возникает, когда вы имеете дело с m2m:
Учти это:
# will return all Model with m2m field 1 Model.objects.filter(m2m_field=1) # will return Model with both 1 AND 2 Model.objects.filter(m2m_field=1).filter(m2m_field=2) # this will NOT work Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2))
Другие примеры приветствуются.
источник
Разница в производительности огромна. Попробуйте и убедитесь.
Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)
на удивление медленнее по сравнению с
Model.objects.filter(condition_a, condition_b, condition_c)
Как упоминалось в Эффективном Django ORM ,
источник
Вы можете использовать модуль подключения, чтобы просмотреть необработанные запросы sql для сравнения. Как объяснил Юджи, по большей части они эквивалентны, как показано здесь:
>>> from django.db import connection >>> samples1 = Unit.objects.filter(color="orange", volume=None) >>> samples2 = Unit.objects.filter(color="orange").filter(volume=None) >>> list(samples1) [] >>> list(samples2) [] >>> for q in connection.queries: ... print q['sql'] ... SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL) SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL) >>>
источник
Этот ответ основан на Django 3.1.
Окружающая обстановка
class Blog(models.Model): blog_id = models.CharField() class Post(models.Model): blog_id = models.ForeignKeyField(Blog) title = models.CharField() pub_year = models.CharField() # Don't use CharField for date in production =]
Blog.objects.filter(post__title="Title A", post__pub_year="2020") # Result: <QuerySet [<Blog: 1>]> Blog.objects.filter(post__title="Title A").filter(post_pub_date="2020) # Result: <QuerySet [<Blog: 1>, [<Blog: 2>]>
Объяснение
Прежде чем я начну что-либо дальше, я должен заметить, что этот ответ основан на ситуации, когда для фильтрации объектов используется «ManyToManyField» или обратный «ForeignKey».
Если вы используете одну и ту же таблицу или «OneToOneField» для фильтрации объектов, то не будет никакой разницы между использованием «Фильтра по нескольким аргументам» или «Цепочки фильтров». Оба они будут работать как фильтр условия «И».
Самый простой способ понять, как использовать «Фильтр с несколькими аргументами» и «Цепочка фильтров», - это запомнить в фильтре «ManyToManyField» или обратном «ForeignKey», что «Фильтр с несколькими аргументами» является условием «И» и «Фильтр» -chain »является условием« ИЛИ ».
Причина, по которой «фильтр с несколькими аргументами» и «цепочка фильтров» настолько различаются, заключается в том, что они извлекают результат из разных таблиц соединения и используют разные условия в операторе запроса.
SELECT * FROM "Book" INNER JOIN ("Post" ON "Book"."id" = "Post"."book_id") WHERE "Post"."Title" = 'Title A' AND "Post"."Public_Year" = '2020'
SELECT * FROM "Book" INNER JOIN "Post" ON ("Book"."id" = "Post"."book_id") INNER JOIN "Post" T1 ON ("Book"."id" = "T1"."book_id") WHERE "Post"."Title" = 'Title A' AND "T1"."Public_Year" = '2020'
Но почему разные условия влияют на результат?
Я считаю, что большинство из нас, кто заходит на эту страницу, включая меня =], придерживается того же предположения при использовании «Фильтра по нескольким аргументам» и «Цепочки фильтров».
Мы считаем, что результат должен быть получен из таблицы, подобной следующей, которая подходит для «Фильтра множественных аргументов». Так что, если вы используете «Фильтр множественных аргументов», вы получите результат, как и ожидали.
Но при работе с «цепочкой фильтров» Django создает другой оператор запроса, который изменяет приведенную выше таблицу на следующую. Кроме того, «Public Year» идентифицируется в разделе «T1» вместо раздела «Post» из-за изменения инструкции запроса.
Но откуда взялась эта странная диаграмма таблицы соединений «цепочка фильтров»?
Я не специалист по базам данных. Приведенное ниже объяснение - это то, что я понял до сих пор после того, как создал ту же структуру базы данных и провел тест с тем же оператором запроса.
На следующей диаграмме показано, откуда взялась эта странная диаграмма таблицы соединений «цепочка фильтров».
База данных сначала создаст объединенную таблицу, сопоставляя строки таблиц «Блог» и «Публикация» одну за другой.
После этого база данных снова выполняет тот же процесс сопоставления, но с использованием таблицы результатов шага 1 для сопоставления с таблицей «T1», которая является той же таблицей «Post».
Вот откуда взялась эта странная диаграмма таблицы соединений «цепочка фильтров».
Заключение
Таким образом, две вещи делают «фильтр с несколькими аргументами» и «цепочку фильтров» разными.
Грязный способ запомнить, как его использовать, - это «Фильтр с несколькими аргументами» - это условие «И», а «Цепочка фильтров» - это условие «ИЛИ» в фильтре «ManyToManyField» или обратном «ForeignKey».
источник
Если вы попадаете на эту страницу в поисках того, как динамически создать набор запросов django с несколькими фильтрами цепочки, но вам нужно, чтобы фильтры были
AND
типа, а неOR
, рассмотрите возможность использования Q-объектов .Пример:
# First filter by type. filters = None if param in CARS: objects = app.models.Car.objects filters = Q(tire=param) elif param in PLANES: objects = app.models.Plane.objects filters = Q(wing=param) # Now filter by location. if location == 'France': filters = filters & Q(quay=location) elif location == 'England': filters = filters & Q(harbor=location) # Finally, generate the actual queryset queryset = objects.filter(filters)
источник
Если требуются a и b, то
and_query_set = Model.objects.filter(a=a, b=b)
если требуется a, а также b, то
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
Официальные документы: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Связанное сообщение: Объединение нескольких filter () в Django, это ошибка?
источник
Есть разница, когда у вас есть запрос к связанному объекту, например
class Book(models.Model): author = models.ForeignKey(Author) name = models.ForeignKey(Region) class Author(models.Model): name = models.ForeignKey(Region)
запрос
Author.objects.filter(book_name='name1',book_name='name2')
возвращает пустой набор
и запросить
Author.objects.filter(book_name='name1').filter(book_name='name2')
возвращает авторов, у которых есть книги с именами "имя1" и "имя2"
подробнее см. https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships
источник
Author.objects.filter(book_name='name1',book_name='name2')
даже не валидный питон, это было быSyntaxError: keyword argument repeated