如何在Django中查询为GROUP BY?

我查询一个模型,

Members.objects.all() 

它回报说

 Eric, Salesman, X-Shop Freddie, Manager, X2-Shop Teddy, Salesman, X2-Shop Sean, Manager, X2-Shop 

我想要的是,要知道最好的Django的方式来激发一个group_by查询我的分贝,就像,

 Members.objects.all().group_by('designation') 

当然哪个不行。 我知道我们可以在“django / db / models / query.py”上做一些技巧,但是我只是好奇地知道如何在不修补的情况下做到这一点。

如果你想要做聚合,你可以使用ORM的聚合特性 :

 from django.db.models import Count Members.objects.values('designation').annotate(dcount=Count('designation')) 

这会导致类似于的查询

 SELECT designation, COUNT(designation) AS dcount FROM members GROUP BY designation 

并且输出将是forms

 [{'designation': 'Salesman', 'dcount': 2}, {'designation': 'Manager', 'dcount': 2}] 

一个简单的解决scheme,但没有一个正确的方法是使用RAW-SQL:

http://docs.djangoproject.com/en/dev/topics/db/sql/#topics-db-sql

另一个解决scheme是使用group_by属性:

 query = Members.objects.all().query query.group_by = ['designation'] results = QuerySet(query=query, model=Members) 

您现在可以迭代结果variables来检索结果。 请注意,group_by没有logging,可能会在未来版本的Django中进行更改。

而…为什么你要使用group_by? 如果您不使用聚合,则可以使用order_by来获得相似的结果。

您需要执行自定义SQL,如下面的代码片段所示:

通过子查询定制SQL

或者在线Django文档中显示的自定义pipe理器中:

添加额外的经理方法

Django不支持通过查询的自由组 。 我以非常糟糕的方式了解到这一点。 ORM不是用来支持像你想做的事情,而不使用自定义SQL。 您仅限于:

  • RAW sql(即MyModel.objects.raw())
  • cr.execute句子(以及手工parsing的结果)。
  • .annotate() (按句子分组是在.annotate()的子模型中执行的,例如聚合lines_count = Count('lines')))。

在查询集qs你可以调用qs.query.group_by = ['field1', 'field2', ...]但是如果你不知道你正在编辑什么查询并且不能保证它会工作,不会破坏QuerySet对象的内部。 此外,它是一个内部(无证)的API,你不应该直接访问,而不会冒着代码与未来的Django版本不兼容的风险。

有一个模块可以让你对Django模型进行分组,并且仍然可以在结果中使用QuerySet: https : //github.com/kako-nawao/django-group-by

例如:

 from django_group_by import GroupByMixin class BookQuerySet(QuerySet, GroupByMixin): pass class Book(Model): title = TextField(...) author = ForeignKey(User, ...) shop = ForeignKey(Shop, ...) price = DecimalField(...) 

 class GroupedBookListView(PaginationMixin, ListView): template_name = 'book/books.html' model = Book paginate_by = 100 def get_queryset(self): return Book.objects.group_by('title', 'author').annotate( shop_count=Count('shop'), price_avg=Avg('price')).order_by( 'name', 'author').distinct() def get_context_data(self, **kwargs): return super().get_context_data(total_count=self.get_queryset().count(), **kwargs) 

'书/ books.html'

 <ul> {% for book in object_list %} <li> <h2>{{ book.title }}</td> <p>{{ book.author.last_name }}, {{ book.author.first_name }}</p> <p>{{ book.shop_count }}</p> <p>{{ book.price_avg }}</p> </li> {% endfor %} </ul> 

annotate / aggregate基本Django查询的区别在于使用相关字段的属性,例如book.author.last_name

如果您需要已组合在一起的实例的PK,请添加以下注释:

 .annotate(pks=ArrayAgg('id')) 

注意: ArrayAgg是从Django 1.9开始提供的Postgres特定函数: https : ArrayAgg

该文件说您可以使用值来分组查询集。

 class Travel(models.Model): interest = models.ForeignKey(Interest) user = models.ForeignKey(User) time = models.DateTimeField(auto_now_add=True) # Find the travel and group by the interest: >>> Travel.objects.values('interest').annotate(Count('user')) <QuerySet [{'interest': 5, 'user__count': 2}, {'interest': 6, 'user__count': 1}]> # the interest(id=5) had been visited for 2 times, # and the interest(id=6) had only been visited for 1 time. >>> Travel.objects.values('interest').annotate(Count('user', distinct=True)) <QuerySet [{'interest': 5, 'user__count': 1}, {'interest': 6, 'user__count': 1}]> # the interest(id=5) had been visited by only one person (but this person had # visited the interest for 2 times 

你可以find所有的书籍,并使用下面的代码将它们分组:

 Book.objects.values('name').annotate(Count('id')).order_by() # ensure you add the order_by() 

你可以在这里看到一些cheet床单。

如果我没有错,你可以使用任何查询设置 .group_by = [' field ']