【Django Models】Django数据查询 汇聚
参见官方文档 ,表定义
https://docs.djangoproject.com/en/dev/topics/db/aggregation/
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() class Publisher(models.Model): name = models.CharField(max_length=300) num_awards = models.IntegerField() class Book(models.Model): name = models.CharField(max_length=300) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) rating = models.FloatField() authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) pubdate = models.DateField() class Store(models.Model): name = models.CharField(max_length=300) books = models.ManyToManyField(Book) registered_users = models.PositiveIntegerField()
1. aggregate范例
1.1 统计本表数据
定义列名
Book.objects.aggregate(average_price=Avg('price')) {'average_price': 34.35}
常用的汇聚函数有Avg,Max,Min,Count,Sum等等
1.2 F条件引入计算
Book.objects.all().aggregate( ... price_per_page=Sum(F('price')/F('pages'), output_field=FloatField())) {'price_per_page': 0.4470664529184653}
1.3 统计外键的字段
>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))
2. annotate
2.1 基本
可以看成是一个反向查找,外键关联汇聚统计。
注意'book'是使用了该外键,与前面表定义可能有点不符
(note how we use 'book'
to specify the Publisher
-> Book
reverse foreign key hop)
>>> from django.db.models import Count >>> pubs = Publisher.objects.annotate(num_books=Count('book')) >>> pubs <QuerySet [<Publisher: BaloneyPress>, <Publisher: SalamiPress>, ...]> >>> pubs[0].num_books
2.2 指定字段统计
如下,指定book表的rating字段统计
Author.objects.annotate(average_rating=Avg('book__rating'))
3. aggregate和annotate差别
aggregate主要是本表字段汇聚计算,annotate是外键关联汇聚计算
4. 汇聚与其他查询条件如filter
4.1 多条汇聚
distinct避免重复计算
>>> q = Book.objects.annotate(Count('authors', distinct=True), Count('store', distinct=True)) >>> q[0].authors__count 2 >>> q[0].store__count 3
4.2 汇聚与filter
汇聚运算和filter运算会按照书写顺序进行运算
条件在后,annotate统计的时候不考虑条件
>>> a, b = Publisher.objects.annotate(num_books=Count('book', distinct=True)).filter(book__rating__gt=3.0) >>> a, a.num_books (<Publisher: A>, 2) >>> b, b.num_books (<Publisher: B>, 2) 条件在前,annotate在过滤后的结果集上统计
>>> a, b = Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book')) >>> a, a.num_books (<Publisher: A>, 2) >>> b, b.num_books (<Publisher: B>, 1)
5. annotate和aggregate串联
Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}
好记性不如烂笔头