시스템을 통과하는 모든 이벤트를 추적하기 위해 트랜잭션 모델을 사용하고 있습니다.
class Transaction(models.Model):
actor = models.ForeignKey(User, related_name="actor")
acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
action_id = models.IntegerField()
......
내 시스템에서 상위 5 명의 배우를 얻으려면 어떻게해야합니까?
SQL에서는 기본적으로
SELECT actor, COUNT(*) as total
FROM Transaction
GROUP BY actor
ORDER BY total DESC
답변
문서에 따르면 다음을 사용해야합니다.
from django.db.models import Count
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
values () : “그룹화 기준”에 사용할 열을 지정합니다.
장고 문서 :
“values () 절을 사용하여 결과 집합에 반환되는 열을 제한하면 주석을 평가하는 방법이 약간 다릅니다. 원본 QuerySet의 각 결과에 대해 주석이 달린 결과를 반환하는 대신 원본 결과는 다음과 같이 그룹화됩니다. values () 절에 지정된 필드의 고유 한 조합 “
annotate () : 그룹화 된 값에 대한 작업을 지정합니다.
장고 문서 :
요약 값을 생성하는 두 번째 방법은 QuerySet의 각 개체에 대해 독립적 인 요약을 생성하는 것입니다. 예를 들어 책 목록을 검색하는 경우 각 책에 기여한 저자 수를 알고 싶을 수 있습니다. 각 책은 저자와 다 대다 관계를 가지고 있습니다. QuerySet의 각 책에 대해이 관계를 요약하려고합니다.
annotate () 절을 사용하여 객체 별 요약을 생성 할 수 있습니다. annotate () 절이 지정되면 QuerySet의 각 객체에 지정된 값이 주석으로 추가됩니다.
order by 절은 자명합니다.
요약하면, 작성자의 쿼리 세트를 생성하여 그룹화하고 주석을 추가하고 (반환 된 값에 추가 필드가 추가됨) 마지막으로이 값을 기준으로 정렬합니다.
자세한 내용은 https://docs.djangoproject.com/en/dev/topics/db/aggregation/ 을 참조하십시오.
참고 : Count를 사용하는 경우 Count에 전달 된 값은 집계에 영향을주지 않고 최종 값에 지정된 이름 만 영향을줍니다. 집계자는 Count에 전달 된 값이 아니라 값의 고유 한 조합 (위에서 언급 한대로)별로 그룹화합니다. 다음 쿼리는 동일합니다.
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
Transaction.objects.all().values('actor').annotate(total=Count('id')).order_by('total')
답변
@Alvaro가 Django의 직접 동등한 for GROUP BY
문에 대답 한 것처럼 :
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
사용하는 것이다 values()
하고 annotate()
다음 방법 :
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
그러나 한 가지 더 지적해야합니다.
모델에 정의 된 기본 순서가있는 경우 class Meta
의 .order_by()
절은 올바른 결과에 대한 의무입니다. 주문할 의도가없는 경우에도 건너 뛸 수 없습니다.
또한 고품질 코드의 경우 . 가없는 경우에도 항상 .order_by()
뒤에 절을 추가하는 것이 좋습니다 . 이러한 접근 방식은 진술을 미래 지향적으로 만들 것입니다 . 향후 변경 사항에 관계없이 의도 한대로 작동합니다 .annotate()
class Meta: ordering
class Meta: ordering
예를 들어 보겠습니다. 모델에 다음이있는 경우 :
class Transaction(models.Model):
actor = models.ForeignKey(User, related_name="actor")
acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
action_id = models.IntegerField()
class Meta:
ordering = ['id']
그렇다면 그러한 접근 방식은 작동하지 않을 것입니다.
Transaction.objects.values('actor').annotate(total=Count('actor'))
Django GROUP BY
는 모든 필드에서 추가 작업 을 수행하기 때문 입니다.class Meta: ordering
쿼리를 인쇄 할 경우 :
>>> print Transaction.objects.values('actor').annotate(total=Count('actor')).query
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
집계가 의도 한대로 작동하지 않을 것이므로이 .order_by()
동작을 지우고 적절한 집계 결과를 얻으려면 절을 사용해야합니다.
참조 : 공식 Django 문서의 기본 순서 또는 order_by ()와의 상호 작용 .