개수 및 그룹화 기준에 해당하는 Django


91

다음과 같은 모델이 있습니다.

class Category(models.Model):
    name = models.CharField(max_length=60)

class Item(models.Model):
    name = models.CharField(max_length=60)
    category = models.ForeignKey(Category)

각 범주에 대한 항목의 개수 (단지 개수)를 선택하기를 원하므로 SQL에서는 다음과 같이 간단합니다.

select category_id, count(id) from item group by category_id

이 "장고 방식"을 수행하는 것과 동등한 것이 있습니까? 아니면 일반 SQL이 유일한 옵션입니까? Django 의 count () 메서드에 익숙 하지만 group by 가 거기에 어떻게 들어 맞는지 모르겠습니다 .



@CiroSantilli 巴拿馬 文件 六四 事件 法轮功 어떻게 중복됩니까? 이 질문은 2008 년에 제기되었으며 당신이 언급 한 것은 2 년 후입니다.
Sergey Golovchenko

현재의 합의는 "품질"로 마무리하는 것입니다. < meta.stackexchange.com/questions/147643/… > "품질"은 측정 할 수 없기 때문에 저는 업 보트를 사용합니다. ;-) 아마도 제목에서 최고의 초보자 Google 키워드에 해당하는 질문이 무엇인지에 대한 것입니다.
치로 틸리는郝海东冠状病六四事件法轮功

답변:


131

방금 발견 한 것처럼 Django 1.1 집계 API로이를 수행하는 방법은 다음과 같습니다.

from django.db.models import Count
theanswer = Item.objects.values('category').annotate(Count('category'))

3
Django의 대부분의 것들처럼, 이것들 중 어느 것도 보는 것이 타당하지 않지만 (Django의 대부분의 것들과는 달리) 한번 실제로 시도한 후에는 굉장했습니다. : P
jsh

3
이 기본 순서가 아닌 order_by()경우 사용해야 합니다 'category'. (Daniel의보다 포괄적 인 답변을 참조하십시오.)
Rick Westera 2013 년

이것이 작동하는 이유 .annotate()는 다음에 약간 다르게 작동.values() 하기 때문입니다 . "그러나 values ​​() 절을 사용하여 결과 집합에 반환되는 열을 제한하는 경우 주석을 평가하는 방법이 약간 다릅니다. 주석을 반환하는 대신 원본 QuerySet의 각 결과에 대한 결과, 원본 결과는 values ​​() 절에 지정된 필드의 고유 한 조합에 따라 그룹화됩니다. "
mgalgs

58

( 업데이트 : 전체 ORM 집계 지원이 이제 Django 1.1에 포함되었습니다 . 개인 API 사용에 대한 아래의 경고에 충실하게 여기에 설명 된 방법은 Django 1.1 버전 이후에서 더 이상 작동하지 않습니다. 이유를 알아 내지 않았습니다. 1.1 이상을 사용하는 경우 어쨌든 실제 집계 API를 사용해야 합니다.)

코어 집계 지원은 이미 1.0에있었습니다. 문서화되지 않고 지원되지 않으며 아직 친숙한 API가 없습니다. 그러나 1.1이 도착할 때까지 어쨌든 그것을 사용할 수있는 방법은 다음과 같습니다.

query_set = Item.objects.extra(select={'count': 'count(1)'}, 
                               order_by=['-count']).values('count', 'category')
query_set.query.group_by = ['category_id']

그런 다음 query_set을 반복하면 반환되는 각 값은 "category"키와 "count"키가있는 사전이됩니다.

여기에서 -count로 주문할 필요는 없습니다. 이것은 단지 어떻게 수행되는지 보여주기 위해 포함 된 것입니다 (쿼리 셋 생성 체인의 다른 곳이 아니라 .extra () 호출에서 수행되어야합니다). 또한 count (1) 대신 count (id)라고 말할 수 있지만 후자가 더 효율적일 수 있습니다.

또한 .query.group_by를 설정할 때 값은 Django 필드 이름 ( 'category')이 아닌 실제 DB 열 이름 ( 'category_id')이어야합니다. 이는 Django 용어가 아닌 DB 용어로 모든 것이 포함되는 수준에서 쿼리 내부를 조정하기 때문입니다.


이전 방법의 경우 +1. 현재 지원되지 않더라도 최소한으로 말하는 것은 깨달음입니다. 정말 놀랍습니다.
공습

docs.djangoproject.com/en/dev/topics/db/aggregation/… 에서 Django Aggregation API를 살펴보십시오. 다른 복잡한 작업을 수행 할 수 있습니다. 여기에서 몇 가지 강력한 예제를 찾을 수 있습니다.
serfer2 2014

@ serfer2 예, 해당 문서는 이미이 답변의 상단에서 링크되었습니다.
Carl Meyer

56

Django 1.1에서 그룹화가 작동하는 방식에 대해 약간 혼란 스러웠 기 때문에 여기서 사용하는 방법에 대해 자세히 설명하겠다고 생각했습니다. 먼저 Michael의 말을 반복합니다.

방금 발견 한 것처럼 Django 1.1 집계 API로이를 수행하는 방법은 다음과 같습니다.

from django.db.models import Count
theanswer = Item.objects.values('category').annotate(Count('category'))

또한 당신이 필요합니다 from django.db.models import Count!

카테고리 만 선택한 다음라는 주석이 추가 category__count됩니다. 기본 순서에 따라 이것이 필요한 전부일 수 있지만 기본 순서가이 이외의 필드를 사용하는 경우 category작동하지 않습니다 . 그 이유는 주문에 필요한 필드도 선택되고 각 행을 고유하게 만들어서 원하는 방식으로 그룹화 할 수 없기 때문입니다. 이 문제를 해결하는 한 가지 빠른 방법은 순서를 재설정하는 것입니다.

Item.objects.values('category').annotate(Count('category')).order_by()

원하는 결과를 정확히 얻을 수 있습니다. 주석의 이름을 설정하려면 다음을 사용할 수 있습니다.

...annotate(mycount = Count('category'))...

그러면 mycount결과에 주석 이 표시됩니다.

그룹화에 관한 다른 모든 것은 나에게 매우 간단했습니다. 더 자세한 정보 는 Django 집계 API 를 확인하세요 .


1
외래 키 필드 Item.objects.values ​​( 'category__category'). annotate (Count ( 'category__category')). order_by ()에 대해 동일한 작업 집합을 수행하는 방법
Mutant

기본 주문 필드가 무엇인지 어떻게 결정합니까?
Bogatyr

2

어때? (느린 것 말고)

counts= [ (c, Item.filter( category=c.id ).count()) for c in Category.objects.all() ]

많은 행을 가져 오더라도 짧다는 장점이 있습니다.


편집하다.

하나의 쿼리 버전입니다. BTW, 이것은 종종 데이터베이스의 SELECT COUNT (*)보다 빠릅니다 . 그것을보십시오.

counts = defaultdict(int)
for i in Item.objects.all():
    counts[i.category] += 1

훌륭하고 짧지 만 각 카테고리에 대해 별도의 데이터베이스 호출을 피하고 싶습니다.
Sergey Golovchenko

이것은 간단한 경우에 정말 좋은 접근 방식입니다. 큰 데이터 세트가 있고 불필요한 데이터를 많이 끌어 내리지 않고 카운트에 따라 주문 + 제한 (즉, 페이지 매김)을 원할 때 떨어집니다.
Carl Meyer

@Carl Meyer : 맞아요-큰 데이터 세트의 경우 강아지 일 수 있습니다. 그러나이를 확인하려면 벤치마킹해야합니다. 또한 지원되지 않는 항목에도 의존하지 않습니다. 지원되지 않는 기능이 지원 될 때까지 일시적으로 작동합니다.
S.Lott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.