장고에서 카운트 주석을 위해 객체를 필터링하는 방법은 무엇입니까?
간단한 모형을 .Event
그리고.Participant
:
class Event(models.Model):
title = models.CharField(max_length=100)
class Participant(models.Model):
event = models.ForeignKey(Event, db_index=True)
is_paid = models.BooleanField(default=False, db_index=True)
이벤트 쿼리에 총 참가자 수를 주석으로 추가하는 것은 쉽습니다.
events = Event.objects.all().annotate(participants=models.Count('participant'))
을 다는 은 다음과 .is_paid=True
?
참가자 수에 관계없이 모든 이벤트를 쿼리해야 합니다. 예를 들어 주석이 달린 결과로 필터링할 필요가 없습니다.있다면,0
참가자들, 괜찮습니다, 저는 그저 필요합니다.0
주석이 달린 값으로
문서의 예제는 개체에 주석을 다는 대신 쿼리에서 제외되기 때문에 여기서는 작동하지 않습니다.0
.
업데이트. 장고 1.8에는 새로운 조건부 표현 기능이 있으므로 이제 다음과 같이 할 수 있습니다.
events = Event.objects.all().annotate(paid_participants=models.Sum(
models.Case(
models.When(participant__is_paid=True, then=1),
default=0,
output_field=models.IntegerField()
)))
업데이트 2.Django 2.0에는 새로운 조건부 집계 기능이 있습니다. 아래의 승인된 답변을 참조하십시오.이것은 Django 3.x에서도 작동합니다.
Django 2.0+의 조건부 집계를 통해 과거에 발생했던 faff의 양을 더욱 줄일 수 있습니다.또한 Postgres'를 사용합니다.filter
논리는 합 사례보다 다소 빠릅니다(20-30% 정도의 숫자가 묶이는 것을 보았습니다).
어쨌든 귀하의 경우 다음과 같은 간단한 것을 검토하고 있습니다.
from django.db.models import Q, Count
events = Event.objects.annotate(
paid_participants=Count('participants', filter=Q(participants__is_paid=True))
)
문서에는 주석 필터링에 대한 별도의 섹션이 있습니다.이것은 조건부 집계와 동일하지만 위의 예와 더 유사합니다.어느 쪽이든, 이것은 제가 전에 했던 평범한 하위 질의보다 훨씬 더 건강합니다.
방금 Django 1.8에 새로운 조건식 기능이 있다는 것을 알게 되었습니다. 그래서 이제 우리는 다음과 같이 할 수 있습니다.
events = Event.objects.all().annotate(paid_participants=models.Sum(
models.Case(
models.When(participant__is_paid=True, then=1),
default=0, output_field=models.IntegerField()
)))
갱신하다
제가 언급한 서브쿼리 접근법은 이제 서브쿼리 표현식을 통해 장고 1.11에서 지원됩니다.
Event.objects.annotate(
num_paid_participants=Subquery(
Participant.objects.filter(
is_paid=True,
event=OuterRef('pk')
).values('event')
.annotate(cnt=Count('pk'))
.values('cnt'),
output_field=models.IntegerField()
)
)
(적절한 인덱싱을 통해) 더 빠르고 쉽게 최적화될 수 있기 때문에 집계(sum+case)보다 이것을 선호합니다.
이전 버전의 경우 다음을 사용하여 동일한 작업을 수행할 수 있습니다.
Event.objects.extra(select={'num_paid_participants': "\
SELECT COUNT(*) \
FROM `myapp_participant` \
WHERE `myapp_participant`.`is_paid` = 1 AND \
`myapp_participant`.`event_id` = `myapp_event`.`id`"
})
저는 당신의 방법을 사용하는 것을 제안하고 싶습니다.Participant
대신 쿼리 집합.
간단히 말해서, 여러분이 원하는 것은 다음과 같습니다.
Participant.objects\
.filter(is_paid=True)\
.values('event')\
.distinct()\
.annotate(models.Count('id'))
전체 예는 다음과 같습니다.
를 생성합니다.
Event
s:event1 = Event.objects.create(title='event1') event2 = Event.objects.create(title='event2')
더하다
Participant
그들에게:part1l = [Participant.objects.create(event=event1, is_paid=((_%2) == 0))\ for _ in range(10)] part2l = [Participant.objects.create(event=event2, is_paid=((_%2) == 0))\ for _ in range(50)]
모두 두모그화룹
Participant
그들의 말에 의하면event
선택사항:Participant.objects.values('event') > <QuerySet [{'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 1}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, {'event': 2}, '...(remaining elements truncated)...']>
여기에는 다음과 같은 구별이 필요합니다.
Participant.objects.values('event').distinct() > <QuerySet [{'event': 1}, {'event': 2}]>
무엇을
.values
그리고..distinct
일은 두 개의 입니다.Participant
.event
에는 한이버는다포함니다됩이 되어 있습니다.Participant
.그 다 버 에 킷 원 세 본 가 포 있 어 있 니 다 습 수 달 주 을 석 버 런 에 킷 음 이 한 로 므 러 으 트 되 함 ▁as 다 ▁they ▁buckets ▁you ▁those 니 ate ▁the ▁annot ▁of ▁contain ▁then 그 ▁can습 ▁set런있▁original 다 수 음달버킷원에
Participant
여기서 우리는 다음의 수를 세고자 합니다.Participant
이것은 단순히 세는 것으로 이루어집니다.id
버킷에 있는 요소의 s(그 때문에)Participant
):Participant.objects\ .values('event')\ .distinct()\ .annotate(models.Count('id')) > <QuerySet [{'event': 1, 'id__count': 10}, {'event': 2, 'id__count': 50}]>
마침내 당신은 오직 원합니다.
Participant
와 함께is_paid
존재True
이전 식 앞에 필터를 추가하면 위에 표시된 식이 생성됩니다.Participant.objects\ .filter(is_paid=True)\ .values('event')\ .distinct()\ .annotate(models.Count('id')) > <QuerySet [{'event': 1, 'id__count': 5}, {'event': 2, 'id__count': 25}]>
유일한 단점은 당신이 그것을 회수해야 한다는 것입니다.Event
나중에 당신은 오직 그것만 가지고 있기 때문에.id
위의 방법으로부터
Django 3.x의 경우 주석 뒤에 필터를 쓰기만 하면 됩니다.
User.objects.values('user_id')
.annotate(sudo_field=models.Count('likes'))
.filter(sudo_field__gt=100)
위에sudo_field
는 사용자 모델의 모델 필드가 아니며 여기서는 좋아요(또는 xyz)가 100개 이상인 사용자를 필터링하고 있습니다.
원하는 결과:
- 보고서에 태스크가 추가된 사용자(할당된 사용자) - 전체 고유 사용자 수
- 보고서에 추가된 태스크가 있지만 청구 가능성이 0보다 큰 태스크의 경우에만 해당하는 사용자.
일반적으로 두 가지 다른 쿼리를 사용해야 합니다.
Task.objects.filter(billable_efforts__gt=0)
Task.objects.all()
하지만 저는 두 가지 모두를 한 번의 질문으로 원합니다.따라서:
Task.objects.values('report__title').annotate(withMoreThanZero=Count('assignee', distinct=True, filter=Q(billable_efforts__gt=0))).annotate(totalUniqueAssignee=Count('assignee', distinct=True))
결과:
<QuerySet [{'report__title': 'TestReport', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}, {'report__title': 'Utilization_Report_April_2019', 'withMoreThanZero': 37, 'totalUniqueAssignee': 50}]>
언급URL : https://stackoverflow.com/questions/30752268/how-to-filter-objects-for-count-annotation-in-django
'programing' 카테고리의 다른 글
Linux 서버에 설치된 Oracle 버전을 찾는 방법(터미널 내) (0) | 2023.06.09 |
---|---|
datetime 인스턴스가 다른 두 datetime 개체 사이에 있는지 확인합니다. (0) | 2023.06.09 |
Initializers are not allowed in ambient contexts error when installing Blueprint (0) | 2023.06.09 |
여러 테스트에 대한 Unit test setUp/tearDown (0) | 2023.06.09 |
임베디드 프로젝트용 C/C++ HTTP 클라이언트 라이브러리 (0) | 2023.06.09 |