Django之ORM操作(聚合 分组、F Q)
Django之ORM操作(聚合 分组、F、Q)
聚合
aggregate() 是 QuerySet 的一个终止子句,也就是说,他返回一个包含一些键值对的字典,在它的后面不可以再进行点(.)操作。
键的名称是聚合值的标识符,只是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
聚合函数的导入
from django.db.models import Max, Min, Sum, Avg, Count
简单使用示例:
查询所有书的平均价格。
1 from django.db.models import Avg, Sum, Max, Min, Count 2 3 ret = models.Book.objects.all().aggregate(Avg("price")) 4 5 >>> {'price__avg': 13.233333} # price__avg 是自动成出来的,前边是聚合的字段,后边是聚合函数的名称。
当需要为聚合值指定一个名称,可以向聚合子句提供它。
from django.db.models import Avg, Sum, Max, Min, Count models.Book.objects.aggregate(average_price=Avg('price')) # average_price 为自己指定的名称.
>>> {'average_price': 13.233333}
当需要生成不止一个聚合时,可以向 aggregate() 子句中添加另一个参数。
查询所有图书价格的平均值、最大值、最小值。
1 from django.db.models import Avg, Sum, Max, Min, Count 2 3 models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price")) # 4 5 >>> {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
查询所有图书中最高的价格和平均价格
1 from django.db.models import Max, Avg 2 3 ret = models.Book.objects.aggregate(Max('price'), avg=Avg('price')) #
分组
现有员工表如下:
需求:
按照部门分组求平均工资
ORM 操作如下:
1 from django.db.models import Avg 2 3 models.Employee.objects.values("dept").annotate(avg=Avg("salary")).values("dept", "avg") #
按照哪个字段分组,就将哪个字段写在 objects 后面的 values 中。
注意:
分组使用的是 annotate(),他不是一个终止子句,他的后边可以跟其他操作。
连表查询
表格如下:
按照部门分组求平均工资:
1 from django.db.models import Avg 2 3 models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg") #
按照部门分组,就从部门表上开始查,聚合函数 Avg() 中写需要查的字段,按照双下划线的方法找到字段。
其他示例:
统计每一本书的作者的数量
1 from app01 import models 2 from django.db.models import Count 3 4 ret = models.Book.objects.annotate(Count('author')).values() #
查询每个出版社出版的图书中价格最低的
方式一:
1 from app01 import models 2 from django.db.models import Min 3 4 ret = models.Publisher.objects.annotate(Min('book__price')).values() #
从出版社表查,聚合函数 Min() 中写需要查询的字段,使用双下划线(__)的方法查询到需要的字段。
方式二:
1 from app01 import models 2 from django.db.models import Min 3 4 ret = models.Book.objects.values('publisher__name').annotate(min=Min('price')) #
从书表中查,objects 后面的 values() 中写分组依据的字段名。然后跟 annotate() 中写聚合函数,聚合函数中写查询的字段。
查询作者数量大于 1 的图书
1 from app01 import models 2 from django.db.models import Count 3 4 ret = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1).values() #
从书表中查询,先统计每一本书的作者的数量,然后使用 filter() 过滤出符合条件的对象。
查询每位作者所出书的总价格
1 from app01 import models 2 from django.db.models import Sum 3 4 ret = models.Author.objects.annotate(Sum('books__price')).values() #
从作者表查询,聚合函数 Sum() 中填写查询的字段。
F
在此之前我们构造的过滤器都只是将字段与某个常量作比较,如果将两个字段做比较时,可以使用 F()。F() 的实例可以在查询中引用字段,来比较同一个 model 实例(对象)中的两个不同字段的值。简单点说就是可以用来动态数据对比查询。
F的导入
from django.db.models import F
查询销量大于库存的图书
from django.db.models import F ret = models.Book.objects.filter(sale__gt=F('kucun')).values() #
F 的用法是 F('字段名'),F() 是用来取值的。
将所有书的销量更新为原来的 2 倍。
1 from app01 import models 2 from django.db.models import F 3 4 ret = models.Book.objects.all().update(sale=F('sale') * 2) #
可以进行翻倍操作。
PS:
知识补充 ---> .update() 更新
仅对选中的 QuerySet 对象进行更新,速度快。
将 id 为 2 的书的销量设置为 100。
1 from app01 import models 2 3 ret = models.Book.objects.filter(id=2).update(sale=100) #
知识补充 ---> .save() 修改后进行保存。
对所有对象都进行保存,操作数据量大,速度慢。
将 id 为 2 的书的销量设置为 1000。
1 from app01 import models 2 3 obj = models.Book.objects.get(id=2) 4 obj.sale='1000' 5 obj.save()
Q
filter() 等方法中的关键字参数查询都是一起进行 and 的,如果需要进行更加复杂的查询,可以使用 Q 对象。
示例:
查询 id 小于等于 3 或者 id 大于等于 6 的书
1 from app01 import models 2 from django.db.models import Q 3 4 ret = models.Book.objects.filter(Q(id__lte=3) | Q(id__gte=6)) #
Q() 写在 filter() 中,使用或(or)查询使每个 Q() 使用管道符(|)连接,管道符表示或(or)的关系。
查询 id 大于等于 10 并且销量大于等于 3000 的书。
1 from app01 import models 2 from django.db.models import Q 3 4 ret = models.Book.objects.filter(Q(id__gte=10) & Q(sale__gte=3000)).values() #
使用 & 连接时表示 and。