Django에서 개수 주석에 대한 개체를 필터링하는 방법은 무엇입니까?
간단한 장고 모델 고려 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. 으로 주석을 달지 않고 쿼리에서 개체를 제외하기 때문입니다 .
최신 정보. 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()
)))
업데이트 2. Django 2.0에는 새로운 조건부 집계 기능이 있습니다. 아래 에서 허용되는 답변을 참조하십시오.
Django 2.0의 조건부 집계 를 사용하면 과거에 있었던 faff의 양을 더 줄일 수 있습니다. 이것은 또한 filter합계 사례보다 다소 빠른 Postgres의 논리를 사용할 것입니다 (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()
)))
최신 정보
내가 언급 한 하위 쿼리 접근 방식은 이제 subquery-expressions 를 통해 Django 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) 보다 이것을 선호합니다 .
이전 버전의 경우 다음을 사용하여 동일한 결과를 얻을 수 있습니다. .extra
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`"
})
대신 쿼리 세트 의 .values방법 을 사용하는 것이 좋습니다 Participant.
간단히 말해서, 원하는 것은 다음과 같습니다.
Participant.objects\
.filter(is_paid=True)\
.values('event')\
.distinct()\
.annotate(models.Count('id'))
완전한 예는 다음과 같습니다.
2
Event초 만들기 :event1 = Event.objects.create(title='event1') event2 = Event.objects.create(title='event2')Participant그들에게 s를 추가하십시오 .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별로 모든 s 그룹화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}]>What
.valuesand.distinctare doing here is that they are creating two buckets ofParticipants grouped by their elementevent. Note that those buckets containParticipant.You can then annotate those buckets as they contain the set of original
Participant. Here we want to count the number ofParticipant, this is simply done by counting theids of the elements in those buckets (since those areParticipant):Participant.objects\ .values('event')\ .distinct()\ .annotate(models.Count('id')) > <QuerySet [{'event': 1, 'id__count': 10}, {'event': 2, 'id__count': 50}]>Finally you want only
Participantwith ais_paidbeingTrue, you may just add a filter in front of the previous expression, and this yield the expression shown above:Participant.objects\ .filter(is_paid=True)\ .values('event')\ .distinct()\ .annotate(models.Count('id')) > <QuerySet [{'event': 1, 'id__count': 5}, {'event': 2, 'id__count': 25}]>
The only drawback is that you have to retrieve the Event afterwards as you only have the id from the method above.
What result I am looking for:
- People (assignee) who have tasks added to a report. - Total Unique count of People
- People who have tasks added to a report but, for task whoe bill ability is more than 0 only.
In general, I would have to use two different queries:
Task.objects.filter(billable_efforts__gt=0)
Task.objects.all()
But I want both in one query. Hence:
Task.objects.values('report__title').annotate(withMoreThanZero=Count('assignee', distinct=True, filter=Q(billable_efforts__gt=0))).annotate(totalUniqueAssignee=Count('assignee', distinct=True))
Result:
<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
'Programming' 카테고리의 다른 글
| 제네릭을 사용하는 Typescript 화살표 함수의 구문은 무엇입니까? (0) | 2020.08.07 |
|---|---|
| Google지도에 선 / 경로 그리기 (0) | 2020.08.07 |
| 값이 JQuery로 선택 목록에 있는지 확인하십시오. (0) | 2020.08.07 |
| 기존 프로젝트를 복사하여 붙여 넣거나 복제하려면 어떻게해야합니까? (0) | 2020.08.07 |
| Microsoft Roslyn과 CodeDom (0) | 2020.08.06 |