2009-04-02 4 views
0

가 나는 두 가지 모델이 카테고리 찾는 :장고 DB, 그 항목 하위 집합에 모두

class Category(models.Model): 
    pass 

class Item(models.Model): 
    cat = models.ForeignKey(Category) 

내가 그 범주의 모든 항목이 항목의 주어진 집합에 속하는 모든 카테고리를 반환하려고를 ID (고마워 함). 예를 들어, 해당 범주와 연관된 모든 항목이 [1,3,5] 집합에있는 ID를 갖는 모든 범주.

Django의 쿼리 구문 (1.1 베타)을 사용하여 어떻게 수행 할 수 있습니까? 이상적으로 모든 작업은 데이터베이스에서 수행되어야합니다.

allowable_items = set([1,3,4]) 

하나 bruteforce 솔루션은 그래서 모든 범주에 대한 item_set을 확인하는 것입니다 :

categories_with_allowable_items = [ 
    category for category in 
    Category.objects.all() if 
    set([item.id for item in category.item_set.all()]) <= allowable_items 
] 

하지만 우리는 '돈

+0

한 번 더 작업을 설명하십시오. 이제는 입력 된 것과 동일한 범주의 하위 집합을 얻고 싶어하는 것 같습니다. –

+0

나는 "해당 카테고리의 모든 항목이 ** item ** ids의 주어진 하위 집합에 속하는 모든 범주"라고 가정합니다. 그렇지 않으면 의미가 없습니다. –

+0

맞습니다. 오타가 수정되었습니다. –

답변

0
Category.objects.filter(item__id__in=[1, 3, 5]) 

장고 외래 키없이 모델에 역의 관계 배를 만듭니다. 관련 이름 (일반적으로 모델 이름은 소문자이지만 수동으로 덮어 쓸 수 있음), 밑줄 두 개 및 쿼리 할 필드 이름을 사용하여 필터링 할 수 있습니다.

+0

사실이지만 OP의 질문은 아닙니다. 그는 세트의 * 항목 ID가 아닌 카테고리를 원하지만 항목 ID 세트에 * 모든 * 관련 항목이있는 카테고리를 원하지 않습니다. – AdamKG

+1

이 경우 다음과 같이 작동 할 수 있습니다. Category.objects.filter (item__id = 1) .filter (item__id = 3) .filter (item__id = 5) –

+0

댓글의 해결책이 여러 조인을 수행하고 있지만 실제로 작동합니다. 감사! –

0

는 다음과 같은 세트로 모든 항목을 필요로 말할 수 categories_with_allowable_items는 항상 allowable_items의 ID를 가진 모든 항목과 관련된 카테고리의 하위 집합이 될 것이므로 모든 항목을 확인해야합니다. 그래서 확인해야합니다 (더 빠를 것입니다) :

categories_with_allowable_items = set([ 
    item.category for item in 
    Item.objects.select_related('category').filter(pk__in=allowable_items) if 
    set([siblingitem.id for siblingitem in item.category.item_set.all()]) <= allowable_items 
]) 

성능이 실제로 문제가되지 않는다면,이 두 가지 (후자는 아니더라도)가 좋을 것입니다. 이러한 테이블이 매우 큰 경우보다 정교한 솔루션을 찾아야 할 수도 있습니다. 특히 파이썬의 오래된 버전을 사용하고 있다면 sets 모듈을 가져와야한다는 것을 기억하십시오.

+0

이상적으로는 모든 작업을 데이터베이스로 푸시하는 방법을 찾고 있지만이 방법이 유용 할 것입니다. –

0

제가 조금 놀았습니다. QuerySet.extra()가 "having"매개 변수를 허용하면 HAVING 절의 원시 SQL 비트로 ORM에서 수행 할 수 있다고 생각합니다. 그러나 그렇게하지는 않습니다. 따라서 데이터베이스를 원한다면 전체 쿼리를 원시 SQL로 작성해야합니다.

편집 : 이것은 당신이 방법이 떼어 얻는 쿼리가

:

from django.db.models import Count 
Category.objects.annotate(num_items=Count('item')).filter(num_items=...) 

문제는 쿼리가 작동하려면, "..."은 상관 할 필요가 있다는 것입니다 하위 카테고리는 각 카테고리에 대해 allowed_items에있는 항목의 수를 찾습니다. .extra는 "가진"인수가 있다면, 당신은 이런 식으로 할 거라고 :

Category.objects.annotate(num_items=Count('item')).extra(having="num_items=(SELECT COUNT(*) FROM app_item WHERE app_item.id in % AND app_item.cat_id = app_category.id)", having_params=[allowed_item_ids]) 
+0

Django 1.1에서는 annotate() 함수를 추가하여 필터에서 집계 함수의 결과를 사용할 수있게했습니다. 예를 들어, Category.objects입니다.annotate (num_items = Count ('item')). 필터 (num_items = 2)는 2 개의 항목이있는 범주를 반환합니다. (그냥 테스트 해본 결과) –

+0

필자는 새로운 주석 기능에 대해 잘 알고 있습니다.이 질문에 대답하려고하는 바로 그 쿼리로 놀고 있습니다. 당신이 할 수없는 것은 2 대신에 무엇이 있어야 하는지를 결정하기위한 상관 된 하위 쿼리 (각 카테고리에 링크 된 allowed_items의 항목 수)입니다. –