How to query as GROUP BY in django?
我有个模特
1 | Members.objects.all() |
And it returns:
ZZU1
我想要知道最好的火焰之路查询我的数据库,比如:
1 | Members.objects.all().group_by('designation') |
不工作的,不工作的我知道我们可以在EDOCX1上做一些作弊,但我很好奇,如果不加标记,我们怎么办?
如果要进行聚合,可以使用ORM的聚合功能:
1 2 | from django.db.models import Count Members.objects.values('designation').annotate(dcount=Count('designation')) |
这将导致类似于
1 2 | SELECT designation, COUNT(designation) AS dcount FROM members GROUP BY designation |
输出的形式是
1 2 | [{'designation': 'Salesman', 'dcount': 2}, {'designation': 'Manager', 'dcount': 2}] |
一个简单的解决方案,但不是正确的方法是使用原始SQL:
1 | results = Members.objects.raw('SELECT * FROM myapp_members GROUP BY designation') |
另一种解决方案是使用
1 2 3 | query = Members.objects.all().query query.group_by = ['designation'] results = QuerySet(query=query, model=Members) |
现在可以迭代results变量来检索结果。请注意,
还有…为什么要使用
还可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | cities = [ {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'}, {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'}, {'name': 'New York', 'population': '20,000,000', 'country': 'USA'}, {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'}, {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'}, ] ... {% regroup cities by country as country_list %} <ul> {% for country in country_list %} <li> {{ country.grouper }} <ul> {% for city in country.list %} <li> {{ city.name }}: {{ city.population }} </li> {% endfor %} </ul> </li> {% endfor %} </ul> |
如下所示:
- 印度
- 孟买:19000000
- 加尔各答:15000000
- 美国
- 纽约:20000000
- 芝加哥:70万
- 日本
- 东京:33000000
我相信它也适用于
来源:https://docs.djangoproject.com/en/2.1/ref/templates/builtins/重新组合
您需要按照以下代码段中的示例执行自定义SQL:
通过子查询自定义SQL
或者在自定义管理器中,如在线django文档所示:
添加额外的管理器方法
有一个模块允许您对django模型进行分组,并在结果中使用查询集:https://github.com/kako-nawao/django-group-by
例如:
1 2 3 4 5 6 7 8 9 10 | from django_group_by import GroupByMixin class BookQuerySet(QuerySet, GroupByMixin): pass class Book(Model): title = TextField(...) author = ForeignKey(User, ...) shop = ForeignKey(Shop, ...) price = DecimalField(...) |
1 2 3 4 5 6 7 8 9 10 11 12 | 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'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <ul> {% for book in object_list %} <li> {{ 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> |
与
如果需要组合在一起的实例的pk,请添加以下注释:
1 | .annotate(pks=ArrayAgg('id')) |
注:
Django不支持自由分组查询。我是以非常糟糕的方式学会的。ORM的设计不支持您想做的事情,而不使用自定义SQL。您仅限于:
- 原始SQL(即myModel.objects.raw())
cr.execute 句(以及对结果的手工分析)。.annotate() (按语句分组在.annotate()的子模型中执行,例如聚合行数=count(‘行’)。
在查询集
文档说明可以使用值对查询集进行分组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
您可以找到所有书籍,并使用以下代码按名称分组:
1 | Book.objects.values('name').annotate(Count('id')).order_by() # ensure you add the order_by() |
你可以在这里看一些厚棉布。
如果我没有误解,您可以使用任何查询集。group_by=['field']
1 2 | from django.db.models import Sum Members.objects.annotate(total=Sum(designation)) |
首先您需要导入SUM然后…