У чому різниця між фільтром із кількома аргументами та ланцюговим фільтром у django?
У чому різниця між фільтром із кількома аргументами та ланцюговим фільтром у django?
Відповіді:
Як ви можете бачити в згенерованих операторах 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
екземпляр?
Випадок, коли результати "декількох аргументів filter-query" відрізняються від "chained-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
може мати більше, ніж утриманців (іншими словами, утриманцем може бути син / дочка одного працівника, тоді як працівник може мати більше одного сина / дочку).
Е-е, припускаючи, що як чоловік-дружина обидва не можуть працювати в 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).
Але семантично обидва для мене різні . перший виглядає як простий розділ σ [шкільна_марка> = 75 І позначка_коледжу> = 75] (Залежне), а друге як повільний вкладений запит: σ [позначка_ школи> = 75] (σ [Значок_коледжу> = 75] (Залежний)).
Якщо потрібен код @codepad
До речі, це подано в документації @ Розділення багатозначних відносин. Я щойно додав приклад, я думаю, це буде корисно для когось нового.
Здебільшого для запиту існує лише один можливий набір результатів.
Використання ланцюгових фільтрів застосовується, коли ви маєте справу з 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)
Як згадувалося в Effective Django ORM ,
- QuerySets підтримують стан у пам'яті
- Зв’язування тригерів клонування, дублювання цього стану
- На жаль, QuerySets підтримує багато стану
- Якщо це можливо, не ланцюжком слід застосовувати більше одного фільтра
Ви можете використовувати модуль підключення, щоб побачити необроблені запити sql для порівняння. Як пояснили Yuji's, здебільшого вони еквівалентні, як показано тут:
>>> 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)
>>>
Якщо ви в кінцевому підсумку на цій сторінці шукали як динамічно нарощувати Джанго QuerySet з декількома фільтрами СЦЕПЛЕНИЕ, але вам потрібні фільтри , щоб мати 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)
якщо потрібні як, так і 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
Пов’язане повідомлення: Це ланцюжок кількох фільтрів () у 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')
повертає авторів, у яких є книги з іменем "name1" і "name2"
детальніше див. на https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships
Author.objects.filter(book_name='name1',book_name='name2')
навіть не дійсний python, це будеSyntaxError: keyword argument repeated