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
.values
and.distinct
are doing here is that they are creating two buckets ofParticipant
s 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 theid
s 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
Participant
with ais_paid
beingTrue
, 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 |