여러 인수가있는 필터와 장고의 체인 필터의 차이점


답변:


60

생성 된 SQL 문에서 볼 수 있듯이 일부는 의심 할 수있는 "OR"이 아닙니다. 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의 예와 같이 조인 된 테이블이 포함되지 않은 경우. 결과는 동일합니다.


20
나는 오늘 아침에 그냥 밀집되어 있다고 생각하지만,이 문장은 "먼저 모든 블로그를 (entry__headline__contains='Lennon')필터링 한 다음 결과 필터에서 필터링 (entry__pub_date__year=2008)하기 때문에" "결과에서 나온 결과"가 정확하다면 왜 entry.headline == 'Bill'.. 노만 entry__headline__contains='Lennon'아웃 필터를 Bill예?
Dustin Wyatt 2016 년

7
나도 혼란스러워. ...이 대답은 단지 잘못된 것 같다,하지만 37 upvotes있다
Personman

1
이 답변은 오해의 소지가 있고 혼란 스럽습니다. 위의 내용은 Yuji의 답변에 명시된대로 M2M 관계를 사용하여 필터링 할 때만 정확합니다. 요점은 예제 항목이 아닌 각 필터 문으로 블로그 항목을 필터링하는 것입니다.
theannouncer

1
블로그 당 여러 항목이있을 수 있기 때문입니다. 언어가 정확합니다. 움직이는 부분을 모두 염두에 두지 않으면 개념이 혼란 스러울 수 있습니다.
DylanYoung

@DustinWyatt 나도 당신과 같은 질문을했지만 마침내 그것을 얻었습니다! 이 페이지 아래에있는 Grijesh Chauhan이 작성한 직원 및 부양 가족 예를 참조하십시오.
theQuestionMan

33

"multiple arguments 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)

두 쿼리 모두 서로 다른 결과를 출력 할 수 있습니다.
referencing-model의 한 행 이상이 referenced-model의 Referencing1동일한 행을 참조 할 수있는 경우 Referenced. 이 경우에 할 수있다 Referenced: Referencing1이 중 하나를 1 : N (일대) 또는 N : (많은 많은) M 관계 선박.

예:

내 응용 프로그램 my_company에는 두 가지 모델 EmployeeDependent. 의 직원은 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 |
                +------+--------+-------------+--------------+  

Dependent 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) 종속

둘째, 쿼리가 필요한 경우 :

부양 가족 중 일부가 대학과 학교에서 구별 마크가있는 모든 직원을 찾으십니까?

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

결과는 동일합니다! 관계형 대수는 다음과 같습니다.

(직원 (school_mark> = 75) 에 따라 다름) (college_mark> = 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>]

Django에서 생성 한 대상 SQL 쿼리를 확인 print qd1.query하고 print qd2.query둘 다 동일합니다 (Django 1.6).

그러나 의미 상 둘 다 나에게 다릅니다 . 첫 번째는 간단한 섹션 σ [school_mark> = 75 AND college_mark> = 75] (종속) 처럼 보이고 두 번째는 느린 중첩 쿼리처럼 보입니다. σ [school_mark> = 75][college_mark> = 75] (종속)).

필요한 경우 코드 @codepad

btw, 그것은 문서 @ Spanning 다중 값 관계에 제공 됩니다. 방금 예제를 추가했습니다. 새로운 사람에게 도움이 될 것이라고 생각합니다.


4
이 유용한 설명에 감사드립니다. 전혀 명확하지 않은 문서의 설명보다 낫습니다.
wim

1
종속 항목을 직접 필터링하는 마지막 표시는 매우 유용합니다. 결과의 변화는 다 대다 관계를 거치는 경우에만 확실히 발생한다는 것을 보여줍니다. 테이블을 직접 쿼리하는 경우 체인 필터는 두 번 빗질하는 것과 같습니다.
Chris

20

대부분의 경우 쿼리에 대해 가능한 결과 집합은 하나만 있습니다.

체인 필터는 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
또 다른 예 : m2m에만 국한되지 않고 일대 다에서도 발생할 수 있습니다. 역방향 조회 (예 : ForeignKey에서 related_name 사용)
wim

설명해 주셔서 감사합니다! 그 전에는 마지막 예제와 두 번째 예제가 같다고 생각했기 때문에 마지막 예제는 저에게 적합하지 않았고 (잘못된 쿼리 결과) 검색에 많은 시간을 보냈습니다. 두 번째 예는 나에게 매우 유용합니다. 또한 Wim이 말했듯이 이것은 내 경우와 같이 역 일대 다 관계에서 사용할 수 있습니다.
zen11625

12

성능 차이가 큽니다. 그것을 시도하고보십시오.

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

의외로 느립니다

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

효과적인 Django ORM 에서 언급했듯이 ,

  • QuerySet은 메모리에 상태를 유지합니다.
  • 체이닝은 복제를 트리거하고 해당 상태를 복제합니다.
  • 불행히도 QuerySet은 많은 상태를 유지합니다.
  • 가능하면 두 개 이상의 필터를 연결하지 마십시오.

8

연결 모듈을 사용하여 비교할 원시 SQL 쿼리를 볼 수 있습니다. Yuji가 설명했듯이 대부분은 다음과 같이 동일합니다.

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

2

이 페이지에서 여러 체인 필터를 사용하여 django 쿼리 세트를 동적으로 빌드하는 방법을 찾고 있지만 필터가 AND대신 유형 이어야하는 경우 Q 객체를OR 사용하는 것이 좋습니다. .

예 :

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

if 또는 elif가 전달되지 않은 경우 filters 변수는 None이되고 & : 'NoneType'및 'Q'에 대해 TypeError : 지원되지 않는 피연산자 유형을 수신합니다. I는 필터 = Q () 필터를 개시
cwhisperer


-4

예를 들어 관련 개체에 대한 요청이있을 때 차이가 있습니다.

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참조하십시오.


5
Author.objects.filter(book_name='name1',book_name='name2')유효한 파이썬도 아닙니다.SyntaxError: keyword argument repeated
wim

1
book_name은 정확히 어디에 정의되어 있습니까? book_set__name을 의미합니까?
DylanYoung
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.