2010-12-10 4 views
18

두 개의 사용자 정의 관리자 메소드가있는 장고 모델이 있습니다. 각각은 객체의 다른 속성을 기반으로 모델 객체의 다른 하위 세트를 반환합니다.두 장고 쿼리 세트의 교차점을 어떻게 찾을 수 있습니까?

class FeatureManager(models.Manager): 

    def without_test_cases(self): 
     return self.get_query_set().annotate(num_test_cases=models.Count('testcase_set')).filter(num_test_cases=0) 

    def standardised(self): 
     return self.get_query_set().annotate(standardised=Count('documentation_set__standard')).filter(standardised__gt=0) 

(모두 testcase_setdocumentation_set이 다른 모델에 ManyToManyField의를 참조하십시오.)

의 검색어, 또는 객체의 단지 목록을 얻을 수있는 방법이 있습니까, 그 각각에 의해 반환 된 검색어 세트의 intersectiond입니다 매니저 방법?

+0

을 사용할 수 각 매니저의 두 필터 기능을 결합하는 것을 어떻게 막을 수 있습니까? –

+0

'Model.objects.managerMethodOne(). managerMethodTwo()'와 같은 의미입니까? 그게 효과가없는 것 같아요. 어쩌면 관리자 방법을 올바르게 작성하지 않았을 수 있습니까? –

+3

필터가 작동합니다. 'Model.objects.filter (this = that) .filter (that = somethingelse)'입니다. 왜 그렇게하지 않니? –

답변

3

리팩터링

class FeatureManager(models.Manager): 

    @staticmethod 
    def _test_cases_eq_0(qs): 
     return qs.annotate(num_test_cases=models.Count('testcase_set')).filter(num_test_cases=0) 

    @staticmethod 
    def _standardized_gt_0(qs): 
     return qs.annotate(standardised=Count('documentation_set__standard')).filter(standardised__gt=0) 

    def without_test_cases(self): 
     return self._test_cases_eq_0(self.get_query_set()) 

    def standardised(self): 
     return self._standardized_gt_0(self.get_query_set()) 

    def intersection(self): 
     return self._test_cases_eq_0(self._standardized_gt_0(self.get_query_set())) 
+0

아! 그래, 그게 영리하다고 내 디자인이 문제일지도 모른다고 생각 했어. –

+7

그가 문제를 해결하든 그렇지 않든, 여전히 두 개의 쿼리 세트의 교차점을 찾는 방법에 대해서는 대답하지 않습니다.이 쿼리 세트는 "장고집의 장고 교차점"에 대한 검색에서 Google이 반환 한 첫 번째 링크입니다. – johannestaas

0

한 가지 방법은 파이썬 세트 모듈을 사용하고 단지 교차 할 수 있습니다 : (첫번째

In [42]: first = Location.objects.filter(id__lt=6) 
In [43]: last = Location.objects.filter(id__gt=4) 

"수입 세트"

는 ID = 5에서 중복 쿼리 세트의 몇을을 비추 경고를 얻는다. .. 음 ... 오 잘). 이제을 구축하고 교차 - 우리가 설정 한 요소를 얻을 :

In [44]: sets.Set(first).intersection(sets.Set(last)) 
Out[44]: Set([<Location: Location object>]) 

이제 정말 5 확인하기 위해 교차 요소의 ID를 얻을 :

In [48]: [s.id for s in sets.Set(first).intersection(sets.Set(last))] 
Out[48]: [5] 

이 분명 데이터베이스를 두 번 히트를하고 쿼리 집합의 모든 요소를 ​​반환합니다. 더 좋은 방법은 관리자의 필터를 연결하는 것이고 하나의 DB 히트 및 SQL 수준에서 필터를 수행 할 수 있어야합니다. QuerySet 및/또는 (QuerySet) 메서드를 볼 수 없습니다. 이 아주 잘 설명되어 있지 않습니다

intersection = Model.objects.filter(...) & Model.objects.filter(...) 

하지만 거의 정확하게 모두의 조건에 사용 AND 조건처럼 행동해야합니다 (이 검색어 세트의 일부를 "설정"을 이용)

+1

'sets'을 사용하지 마십시오; ''set'' (불변의 경우''frozenset')가 더 좋습니다. –

40

대부분의 경우 그냥 쓸 수 있습니다 검색어. 관련 코드 : https://github.com/django/django/blob/1.8c1/django/db/models/query.py#L203

+0

그래, 해봤지만 작동하지 않는 것 같아. 나는 더 큰 queryset에없는 것을 포함하여 더 작은 queryset의 모든 객체를 가진 queryset을 얻는 것처럼 보였습니다. –

+0

다음과 같이 할 수 있습니다 :'intersection = Model.objects.filter (...) & Model.objects.filter (...)'그리고'HttpResponse ("% s"% intersection.query)를 반환하십시오. 장고가 두 쿼리를 하나로 결합 할 때 장고가하고있는 일을 쉽게 파악할 수있게 해줍니다. –

+0

괜찮 으면하지만 고유 한 행을 가져올 수 없습니다. –

2

이없는 데이터베이스에, 파이썬에서 그것을하고 싶은 경우 : 당신이 추가 된 주석에 queriesdue에 다른 주석을 사용하는 경우

intersection = set(queryset1) & set(queryset2) 

문제점 인 것은 객체가 다를 수 있음 ...

0

당신은 정말,이 말아야 카운트가 제로 여부에 기준으로 필터링하는 주석을 사용하는 경우 d 작업 대신

class FeatureManager(models.Manager): 

    def without_test_cases(self): 
     return self.get_query_set().filter(testcase__pk__isnull=True) 

    def standardised(self): 
     return self.get_query_set().filter(documentation_set__standard__isnull=False) 

더 이상 주석을 걱정하지 않으므로 두 쿼리가 매우 원활하게 교차해야합니다.

+0

아,보세요. '표준화 된'쿼리가 작동한다고 생각하지 마십시오. 표준이 아닌 관련 문서 *가있는 기능을 선택합니다. * 관련 표준 *이없는 기능을 선택할 수 있습니다. –

4

저는 qs1.filter (pk__in = qs2)가 (일반적으로) 작동해야한다고 생각합니다. 그것은 나를 위해 비슷한 경우에 작동하는 것, 그것이 작동하고, 생성 된 쿼리가 제정신처럼 보입니다. (당신의 쿼리 세트 중 하나가 값()을 사용하여 프라이 머리 키 컬럼이나 이상한 것을 선택하지 않으면, 그것이 깨질 것이라고 생각할 수 있습니다 ...) 당신은 단지 같은 것을 할 수

19

:

intersection = queryset1 & queryset2 

노동 조합은 단지 장고 1.11 당으로 |

+0

감사합니다. 작동합니다! 하지만 그것은 슬라이스 queryset에서 작동하지 않습니다 –

4

에 의해 &를 교체하려면, 지금은 기능 intersection()

>>> qs1.intersection(qs2, qs3) 
관련 문제