2013-06-16 6 views
11

Django의 filter() 메서드가 어떻게 작동하는지 매우 기본적이고 근본적인 것이 없다고 생각합니다.관련 모델 필드의 장고 필터()

사용하여 다음과 같은 모델 :

len(Collection.objects.filter(item__flag=True)) 
:
class Collection(models.Model): 
    pass 

class Item(models.Model): 
    flag = models.BooleanField() 
    collection = models.ForeignKey(Collection) 

과 질문의 하단에있는 채우기() 함수를 호출하여 제공하는 데이터와

에서, ./manage.py 쉘에서 다음을 실행하십시오

필자가 기대하는 바는 flag = True 인 항목이 하나 이상있는 컬렉션의 수인 "2"를 인쇄한다는 것이 었습니다. 이 기대는 https://docs.djangoproject.com/en/1.5/topics/db/queries/#lookups-that-span-relationships의 문서를 기반으로합니다. 예를 들어 "이 예제는 이름이 '비틀즈 블로그'인 블로그로 모든 항목 개체를 검색합니다.

그러나 위의 호출은 실제로 flag = True 인 Item 레코드의 수인 "6"을 인쇄합니다. 실제로 반환되는 객체는 Collection 객체입니다. 그것은 동일한 컬렉션 개체를 여러 번, 해당 항목 레코드에 대해 한 번 flag = True로 반환하는 것 같습니다. 진정한 인쇄

queryset = Collection.objects.filter(item__flag=True) 
queryset[0] == queryset[1] 

:이은에 의해 확인 될 수있다.

올바른 동작입니까? 그렇다면 그 이유는 무엇입니까? 그것이 예상되는 것이라면, 문서는 엄격하게 해석 될 수 있지만 각 객체가 여러 번 반환 될 수 있다고 말하는 것은 생략됩니다.

여기에 관련된 예가 있습니다. 이는 매우 놀랍거나 (명백히 잘못된) 행동입니다. 이 경우의 저를 잡은 곳이 exclude() 호출은 커스텀 모델 관리자에 의해 추가되는시키고 호출자 후 필터()을 첨가 하였다

from django.db.models import Count  
[coll.count for coll in Collection.objects.filter(item__flag=True).annotate(count=Count("item"))] 
[coll.count for coll in Collection.objects.exclude(item=None).filter(item__flag=True).annotate(count=Count("item"))] 

제 케이스 지문 "[1,2,4]" , 두 번째 줄에는 "[8,16]"이 표시됩니다.

채우기 기능 :

def populate(): 
    Collection.objects.all().delete() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 
    item = Item(collection=collection, flag=True) 
    item.save() 

    collection = Collection() 
    collection.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 
    item = Item(collection=collection, flag=False) 
    item.save() 

답변

12

그것은이 두 부분이있다 밝혀졌습니다. 기본적으로

이하는 검색어 세트가 중복 행을 제거하지 않을 것이다 : 첫째는 의사가 말한다하는 별개의() 메소드이다. 실제로는 Blog.objects.all()과 같은 간단한 쿼리는 중복 결과 행의 가능성을 소개하지 않기 때문에 거의 문제가되지 않습니다. 그러나 쿼리가 여러 테이블에 걸쳐있는 경우 은 QuerySet을 평가할 때 중복 결과를 얻을 수 있습니다. 그 때 당신은 distinct()를 사용합니다. 예상 "2"로

다음 출력 :

len(Collection.objects.filter(item__flag=True).distinct()) 

그러나,이 주석을 사용하여, 내가 준 더 복잡한 예에 도움이되지 않습니다(). 알려진 문제의 사례 인 것으로 밝혀졌습니다 : https://code.djangoproject.com/ticket/10060.

관련 문제