2

에 따라 단순화 된 내 모델의 버전 카운트 또는 그가 소유 한 Flight 오브젝트의 destination 필드에 각각 대응하는 Flight 오브젝트의 주석이 붙습니다.는 다음 조건

예를 들어 사용자가 3 번 비행 한 경우 (LAX-LHR, LHR-CDGCDG-JFK)를 가정합니다. 그럼 난 다음 개체를 반환하는 쿼리 싶습니다 위에서

[LHR, id__count=2}, {CDG, id__count=2}, {LAX, id__count=1}, {JFK, id__count=1}] 

을, 세 개의 문자 코드는 Airport 개체 또는 모든 필드에 서있다.

일반적으로, User의 수천 Airport들과 Flight의 수만있을 수있다, 그래서 바람직하게는 단일 데이터베이스 쿼리에, for 루프와 문 경우 확실한 해결책보다 더 효율적 무언가를 추구하고있다. 초기 filter는 자신의 항공편을 어딘가에 표시하는 공항을 유지하기 때문에

Airport.objects.filter(
    Q(origins__owner=user) | Q(destinations__owner=user) 
) 
.distinct() 
.annotate(
    id__count=Count('origins', distinct=True) + Count('destinations', distinct=True) 
).order_by('-id__count') 

이 단 하나의 사용자와 완벽하게 작동합니다 :

나의 현재 진행이 쿼리입니다. 그러나 여러 사용자가있을 경우 모든 사용자의 항공편이 포함되므로 분명히 실패합니다. 단지 Count에 어떤 방법이 필요합니다. owner=user이 인 특정 User 개체 인 특정 속성을 따르는 객체 인 Flight입니다.


편집 : this page in the Djnago documentation를 읽은 후, 필요에 따라 먼저 필터 퍼팅이 일을해야 것 같다. 하지만 적어도 Q 객체를 사용할 때는 그렇지 않습니다. 다음과 같이 매우 혼란스러운 결과를 발견했습니다. 이 정확히 내가 무엇을하지 않습니다 (

Airport.objects.filter(origins__owner=user).annotate(num_origins=Count('origins')) 

:이 쿼리를 사용하는 경우

, 즉 오직 다음 작동, 기원을보고하고, num_origins 필드 수는 만 항공편은 user 지정에 속하는 나는 아무것도 할 수 없지만, 또는 결합 된 두 개의 Q 객체에 단일 필터를 교체 할 때

즉, 카운트는 그 기원 특정 Airport입니다 항공편을 포함하기 때문에 필요하지만, 제대로 User의 필터링 않습니다.)

을하지만,

Airport.objects.filter(Q(origins__owner=user) | Q(destinations__owner=user)).annotate(num_origins=Count('origins')) 

이제 모든 사용자가 속한 항공편을 계산합니다! 주석 객체는 Q 객체를 사용할 때 필터에 대해 "잊어 버린"것처럼 보입니다. 여기서 무슨 일이 일어나고있는거야?

+0

가 왜 비행 개체의 소유자 키에 대한 관련 이름을 추가하지 않은 : 당신이 장고 (2)를 사용하는 경우 Count에 필터 인수를 전달할 수 있기 때문에

는, 그것은 여전히 ​​간단하다? 그런 다음 모든 사용자의 항공편을 가져 와서 별개의 광고를 적용하여 별개의 항공편 수만 사용할 수 있습니다. –

+0

@ChağatayBarın 소유자 필드에 대한 관련 이름을 추가했지만 사용 방법을 여전히 볼 수 없습니다. 좀 더 설명해 주시겠습니까? 감사. – jc315

답변

2

난 당신이 조건식에이를 수 있다고 생각 다음 When 절은 처음 할 같은 필터를 반복되어

from django.db.models import Case, When 

Airport.objects.filter(
    Q(origins__owner=user) | Q(destinations__owner=user) 
).annotate(
    num_origins=Count(
     Case(When(Q(origin__owner=user), then=1, else=0)), 
    ), 
    num_destinations=Count(
     Case(When(Q(destination__owner=user), then=1, else=0)), 
    ) 
) 

참고. 실제로 대신이 작업을 수행하는 것이 더 효율적이 될 수있다 (당신은 아마 찾아 결과 SQL 쿼리를 검사 할 필요) :

Airport.objects.annotate(
    num_origins=Count(
     Case(When(Q(origin__owner=user), then=1, else=0)), 
    ), 
    num_destinations=Count(
     Case(When(Q(destination__owner=user), then=1, else=0)), 
    ) 
).filter(Q(num_origins__gt=0) | Q(num_destinations__gt=0)) 

즉, 모든 항공편에 주석을 다음 카운트가 0이었던 사람을 필터링합니다.

그런 다음 num_originsnum_destinations을 파이썬으로 추가 할 수 있습니다.

Airport.objects.annotate(
    num_origins=Count('origins', filter=Q(origin__owner=user), distinct=True), 
    num_destinations=Count('destinations', filter=Q(destination__owner=user), disctinct=True) 
).filter(Q(num_origins__gt=0) | Q(num_destinations__gt=0)) 
+0

답변 주셔서 감사합니다. 그러나 첫 번째 옵션을 사용할 수 없습니다. 실제로 else = 0 대신에'default = 0'을 의미한다고 생각합니다. 그렇더라도 카운트가 틀리며 사용자 필터를 무시하는 것처럼 보입니다. 이것이 데이터베이스 문제 일 수 있습니까? 저는 현재 SQLite를 사용하고 있으며 계속 사용하려고 합니다만 도움이된다면 MySQL로 이동할 수 있습니다. 어쨌든 다음에는 장고 2.0으로 업그레이드하고 두 번째 옵션을 사용해 보겠습니다. – jc315

+0

Django 2.0으로 업그레이드했고 두 번째 옵션이 작동합니다! 그러나 몇 가지 오타가 있습니다. 'Count'의 첫 번째 인수는 'originins'와 'destinations'이어야하며 'distinct = True'도 포함해야합니다. 이러한 실수를 바로 잡으면 나는 그 대답을 받아 들일 것입니다. – jc315

+0

귀하의 의견에 따라 편집했습니다. 첫 번째 접근 방식이 효과가 없었던 이유는 너무도 확실하지 않습니다. 코드가 작동하더라도 SQLite는 프로덕션 환경에서 사용하지 않는 것이 좋습니다. Postgres 또는 MySQL을 사용하는 것이 더 좋습니다. – solarissmoke

0

당신은 이것을 시도 할 수 있습니까? 나는 셸에서 테스트하지 않았으므로 'distinct_flights'리스트 구조에 대해 확신하지는 못했지만 아이디어를 얻을 수 있습니다.

# This is all of the distinct flights of your users. 
distinct_flights = Flight.objects.filter(owner__in=[user1.id, user2.id]).distinct().values_list('origin','destination') 

# This is all of the airports included in the flights above. 
Airport.objects.filter(
    Q(origins__in=distinct_flights['origin'])|| 
    Q(destination__in=distinct_flights['destination']) 
) 

# The rest is annotation from those airports as you did before. You can annotate it on the above query again. 
+0

고마워요.하지만 이런 종류의 구조는 모든 사용자의 항공편 수를 세고 있습니다. 필터에서 Q 객체를 사용하지 않으면 작동하며 주석은 지정된 사용자의 비행 만 계산합니다. 그러나 Q 객체를 or과 결합하면 주석은 모든 사용자의 비행을 계산합니다. 내 편집을 참조하십시오. – jc315