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

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

Ответ 1

Как видно из сгенерированных операторов SQL, разница не в "ИЛИ", как могут подозревать некоторые. Именно так ГДЕ и СОЕДИНЯЕТСЯ.

Пример 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. Результат тот же.

Ответ 2

Случай, когда результаты "множественных аргументов filter-query" различаются, а затем "clained-filter-query", следующие:

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

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

    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 может быть больше, чем иждивенцев (другими словами, зависимым может быть сын/дочь одного сотрудника, а у сотрудника может быть более одного сына/дочери).
Ehh, предполагая, что жена мужа и жена не могут работать в my_company. Я взял пример 1: m

Итак, 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" есть метки отличия как в колледже, так и в школе. Реляционная алгебра:

Сотрудник (school_mark >= 75 AND college_mark >= 75) Dependent

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

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

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

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

(Employee (school_mark >= 75) Dependent) (college_mark >= 75) Dependent

Примечание:

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] (зависимый)).

Если вам нужно Code @codepad

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

Ответ 6

Если на этой странице вы узнаете, как динамически создавать 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)

Ответ 7

из django.db.models import Q

& is = Boolean (i) | is = Boolean (o)

models.objects.filter(Q (id = self.kwargs ['pk']) и Q (date = self.kwargs ['date'])) models.objects.filter(Q (id = self.kwargs ['pk) ']) | Q (date = self.kwargs [' date ']))

Ответ 9

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

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