Разница между фильтром с несколькими аргументами и цепным фильтром в Django - PullRequest
58 голосов
/ 04 апреля 2011

В чем разница между фильтром с несколькими аргументами и цепным фильтром в django?

Ответы [ 7 ]

42 голосов
/ 14 июня 2012

Как видно из сгенерированных операторов SQL, разница не в «ИЛИ», как могут подозревать некоторые.Это то, как расположены WHERE и JOIN.

Example1 (та же самая объединенная таблица): из 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)

Это даст вам все блоги, которые имеют one запись с обоими (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.Результат тот же.

16 голосов
/ 26 января 2014

Случай, в котором результаты «фильтра-запроса с несколькими аргументами» отличаются от «цепного фильтра-запроса», следующие:

Выбор ссылочных объектов на основе ссылок на объекты и отношения - один-ко-многим (или многие-ко-многим).

Несколько фильтров:

    Referenced.filter(referencing1_a=x, referencing1_b=y)
    #  same referencing model   ^^                ^^

Цепные фильтры:

    Referenced.filter(referencing1_a=x).filter(referencing1_b=y)

Оба запроса могут выдавать разные результаты:
Если больше одного строки в модели ссылок Referencing1 могут ссылаться на одну и ту же строку в ссылки-модель Referenced. Это может иметь место в Referenced: Referencing1 имеют 1: N (один ко многим) или N: M (много ко многим) отношение корабль.

Пример:

Рассмотрим мое приложение my_company имеет две модели Employee и Dependent. У сотрудника в my_company может быть больше, чем иждивенцев (другими словами, иждивенцем может быть сын / дочь одного работника, в то время как у сотрудника может быть более одного сына / дочери).
Эхх, если предположить, что муж-жена оба не могут работать в my_company. Я взял 1: м пример

Итак, Employee является ссылочной моделью, на которую может ссылаться более чем Dependent, которая является ссылочной моделью. Теперь рассмотрим состояние отношения следующим образом:

Employee:        Dependent:
+------+        +------+--------+-------------+--------------+
| name |        | name | E-name | school_mark | college_mark |
+------+        +------+--------+-------------+--------------+
| A    |        | a1   |   A    |          79 |           81 |
| B    |        | b1   |   B    |          80 |           60 |
+------+        | b2   |   B    |          68 |           86 |
                +------+--------+-------------+--------------+  

Зависимый a1 относится к работнику A, а зависимый b1, b2 относится к работнику B.

Теперь мой запрос:

Найти всех сотрудников, имеющих сына / дочь, имеющих отличительные знаки (скажем,> = 75%) как в колледже, так и в школе?

>>> Employee.objects.filter(dependent__school_mark__gte=75,
...                         dependent__college_mark__gte=75)

[<Employee: A>]

Вывод «A» зависимый «a1» имеет отличительные знаки как в колледже, так и в школе зависит от сотрудника «A». Примечание «B» не выбрано, потому что ни один из детей «B» не имеет отличительных знаков как в колледже, так и в школе. Реляционная алгебра:

Сотрудник (школьная отметка> = 75 И отметка колледжа> = 75) Зависимая

Во втором случае мне нужен запрос:

Найти всех сотрудников, чьи некоторые из иждивенцев имеют отличительные знаки в колледже и школе?

>>> 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>]

результат тот же! Реляционная алгебра может быть:

(Сотрудник (школьный знак> = 75) Зависимый) (колледж> = 75) Зависимый

Примечание следующее:

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).

Но семантически оба они отличаются от me . первый выглядит как простой раздел σ [school_mark> = 75 AND College_mark> = 75] (зависимый), а второй похож на медленный вложенный запрос: σ [school_mark> = 75] [College_mark> = 75] (зависит)).

Если нужно Код @ кодовая панель

Кстати, это дано в документации @ Охват многозначных отношений Я только что добавил пример, думаю, это будет полезно для кого-то нового.

15 голосов
/ 04 апреля 2011

В большинстве случаев существует только один возможный набор результатов для запроса.

Использование фильтров цепочки происходит, когда вы имеете дело с 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))

Другие примеры приветствуются.

9 голосов
/ 03 июня 2014

Разница в производительности огромна.Попробуйте и посмотрите.

Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)

на удивление медленный по сравнению с

Model.objects.filter(condition_a, condition_b, condition_c)

Как уже упоминалось в "Эффективном Django ORM",

  • QuerySets поддерживает состояние в памяти
  • Цепочка запускает клонирование, дублируя это состояние
  • К сожалению, QuerySets поддерживает много состояния1021 *
  • Если возможно, не цепляйте более одного фильтра
6 голосов
/ 04 апреля 2011

Вы можете использовать модуль подключения, чтобы увидеть необработанные запросы 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)
>>> 
1 голос
/ 09 июля 2015

Если вы оказались на этой странице в поисках того, как динамически создать набор запросов 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)
0 голосов
/ 30 января 2012

Есть разница, когда у вас есть запрос к связанному объекту, например

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')

возвращает авторов, у которых есть книги с именами «name1» и «name2»

подробности смотрите на https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships

...