如何在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 ']