2017-10-01 4 views
0

을 설정합니다. 하나의 주석은 A 행이 부모 인 B 행의 숫자 여야합니다. 다른 주석은 해당 A 객체가 부모 인 B 행을 나타내야하며, 에 C 유형의 객체가 적어도 n 개 있어야합니다.주석 달기 장고 쿼리는 역 외국 키를 다음과 같이 간단한 모델을 감안할 때

Table A 
id 
0 
1 

Table B 
id parent 
0 0 
1 0 

Table C 
id parent 
0 0 
1 0 
2 1 
3 1 
4 1 

내가 ID 0과 A 객체가 두 B 개체가 같은 형태 [(0, 2, 1), (1, 0, 0)]의 결과를 얻을 수 있도록하고 싶습니다 : 예를 들어

다음 데이터베이스와 n = 3 고려 하나에는 적어도 세 개의 관련된 객체가 있습니다. ID가 1 인 A 개체에는 B 개체가 없으므로 행이 적어도 하나있는 B 개체도 없습니다.

첫 번째 주석은 간단하다 :

A.objects.annotate(annotation_1=Count('b_set')) 

은 내가 지금 설계하려고하는 두 번째 주석이다. B 객체가 적어도 하나의 C 객체가 다음 것처럼 어디 AB 행의 수를 계산하는 데 성공했다 :

A.objects.annotate(annotation_2=Count('b_set__c_set__parent', distinct=True)) 

을하지만 다른 최소한의 관련 집합 크기와 함께 할 수있는 방법을 알아낼 수 없습니다 하나보다. 바라건대 여기 누군가가 올바른 방향으로 나를 가리킬 수 있습니다. 내가 생각하고 있던 한 가지 방법은 A 행 대신 쿼리의 B 개체에 주석을 달고 주석 메서드의 기본값을 사용하는 것으로 생각했지만 어떤 리소스도 찾을 수 없었습니다.

답변

1

이것은 장고 1.11의 한계에서 복잡한 쿼리입니다.

from django.db.models import Count 

sub_qs = (
    C.objects 
    .values('parent') 
    .annotate(c_count=Count('id')) 
    .order_by() 
    .filter(c_count__gte=n) 
    .values('parent') 
) 
qs = B.objects.filter(id__in=sub_qs).values('parent_id').annotate(cnt=Count('id')) 
qs_map = {x['parent_id']: x['cnt'] for x in qs} 
rows = list(A.objects.annotate(annotation_1=Count('b_set'))) 
for row in rows: 
    row.annotation_2 = qs_map.get(row.id, 0) 

목록 rows은 결과입니다 : 나는 두 개의 쿼리에 의해 그것을 할과의 검색어와 같은 뷰에서 사용할 수있는 하나 개의 목록에 결과를 결합하기로 결정했다. 더 복잡한 qs.query는 상대적으로 간단한 SQL로 컴파일됩니다.

>>> print(str(qs.query)) 
SELECT app_b.parent_id, COUNT(app_b.id) AS cnt 
FROM app_b 
WHERE app_b.id IN (
    SELECT U0.parent_id AS Col1 FROM app_c U0 
    GROUP BY U0.parent_id HAVING COUNT(U0.id) >= 3 
) 
GROUP BY app_b.parent_id;    -- (added white space and removed double quotes) 

이 간단한 솔루션은 더 쉽게 수정하고 테스트 할 수 있습니다.


참고 : 하나의 쿼리로 해결할 수도 있지만 유용하지는 않습니다. 이유 : Subquery 및 OuterRef()가 필요합니다. 그것들은 훌륭하지만 일반적으로 집계의 Count()는 결합 분석과 함께 컴파일 된 쿼리에서 지원되지 않습니다. 하위 쿼리는 Django에 의해 컴파일 될 수있는 lookup ...__in=... to로 분리 될 수 있지만, OuterRef()를 사용할 수는 없습니다. OutRef없이 쓰면 복잡하지 않은 최적의 중첩 SQL이므로 시간 복잡도는 많은 (또는 모든) 데이터베이스 백엔드에 대해 A 테이블 크기로 O (n) 일 것입니다. 검증되지 않은.