聚合查询(aggregate)
Django 使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum(首字母大写)。
from django.db.models import Avg,Max,Min,Count,Sum # 引入函数
聚合查询返回值的数据类型是字典。
聚合函数 aggregate() 是 QuerySet 的一个终止子句, 生成的一个汇总值,相当于 count()。
使用 aggregate() 后,数据类型就变为字典,不能再使用 QuerySet 数据类型的一些 API 了。
日期数据类型(DateField)可以用 Max 和 Min。
返回的字典中:键的名称默认是(属性名称加上__聚合函数名),值是计算出来的聚合值。
aggregate(别名 = 聚合函数名("属性名称"))
计算所有图书的平均价格:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Book.objects.aggregate(Avg("price")) print(res, type(res)) return HttpResponse(res)
结果如下:
January 31, 2022 - 17:33:59 Django version 4.0.1, using settings 'app02.settings' Starting development server at http://127.0.0.1:8003/ Quit the server with CTRL-BREAK. {'price__avg': Decimal('176.666667')} <class 'dict'> [31/Jan/2022 17:34:05] "GET /add_book/ HTTP/1.1" 200 10
计算所有图书的数量、最贵价格和最便宜价格:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res=models.Book.objects.aggregate(c=Count("id"),max=Max("price"),min=Min("price")) print(res,type(res)) return HttpResponse(res)
结果如下:
January 31, 2022 - 17:36:12 Django version 4.0.1, using settings 'app02.settings' Starting development server at http://127.0.0.1:8003/ Quit the server with CTRL-BREAK. {'c': 6, 'max': Decimal('200.00'), 'min': Decimal('60.00')} <class 'dict'> [31/Jan/2022 17:36:17] "GET /add_book/ HTTP/1.1" 200 7
分组查询(annotate)
分组查询一般会用到聚合函数,所以使用前要先从 django.db.models 引入 Avg,Max,Min,Count,Sum(首字母大写)。
from django.db.models import Avg,Max,Min,Count,Sum # 引入函数
返回值:
MysqL 中的 limit 相当于 ORM 中的 QuerySet 数据类型的切片。
注意:
annotate 里面放聚合函数。
-
values 或者 values_list 放在 annotate 前面:values 或者 values_list 是声明以什么字段分组,annotate 执行分组。
-
values 或者 values_list 放在annotate后面: annotate 表示直接以当前表的pk执行分组,values 或者 values_list 表示查询哪些字段, 并且要将 annotate 里的聚合函数起别名,在 values 或者 values_list 里写其别名。
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Publish.objects.values("name").annotate(in_price = Min("book__price")) print(res) return HttpResponse(res)
January 31, 2022 - 18:43:38 Django version 4.0.1, using settings 'app02.settings' Starting development server at http://127.0.0.1:8003/ Quit the server with CTRL-BREAK. {'c': 6, 'max': Decimal('200.00'), 'min': Decimal('60.00')} <class 'dict'> [31/Jan/2022 18:44:59] "GET /add_book/ HTTP/1.1" 200 7
统计每一本书的作者个数:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Book.objects.annotate(c = Count("authors__name")).values("title","c") print(res) return HttpResponse(res)
命令行中可以看到以下输出:
{'title': '入门教程', 'c': 2}{'title': 'Django入门教程', 'c': 3}{'title': 'Python高级教程', 'c': 1}{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 0}
Starting development server at http://127.0.0.1:8003/ Quit the server with CTRL-BREAK. <QuerySet [{'title': '入门教程', 'c': 2}, {'title': 'Django入门教程', 'c': 3}, {'title': 'Python高级教程', 'c': 1}, {'title': '入门教程', 'c': 0}, {'title': '入门教程', 'c': 0}, {'title': '入门教程', 'c': 0}]> [31/Jan/2022 18:49:20] "GET /add_book/ HTTP/1.1" 200 210
统计每一本以"入"开头的书籍的作者个数:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Book.objects.filter(title__startswith="入").annotate(c = Count("authors__name")).values("title","c") print(res) return HttpResponse(res)
{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 2}{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 0}
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Book.objects.annotate(c = Count("authors__name")).filter(c__gt=0).values("title","c") print(res) return HttpResponse(res)
命令行中可以看到以下输出:
{'title': '入门教程', 'c': 2}{'title': 'Django入门教程', 'c': 3}{'title': 'Python高级教程', 'c': 1}
根据一本图书作者数量的多少对查询集 QuerySet 进行降序排序:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Book.objects.annotate(c = Count("authors__name")).order_by("-c").values("title","c") print(res) return HttpResponse(res)
{'title': 'Django入门教程', 'c': 3}{'title': '入门教程', 'c': 2}{'title': 'Python高级教程', 'c': 1}{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 0}{'title': '入门教程', 'c': 0}
查询各个作者出的书的总价格:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import Avg,Max,Min,Count,Sum # 引入函数 def add_book(request): res = models.Author.objects.annotate(all = Sum("book__price")).values("name","all") print(res) return HttpResponse(res)
{'name': '张某某', 'all': Decimal('400.00')}{'name': '李某某', 'all': Decimal('260.00')}{'name': '王某某', 'all': Decimal('400.00')}{'name': '韩某某', 'all': None}
F() 查询
F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
之前构造的过滤器都只是将字段值与某个常量做比较,如果想要对两个字段的值做比较,就需要用到 F()。
使用前要先从 django.db.models 引入 F:
from django.db.models import F
用法:
F("字段名称")
F 动态获取对象字段的值,可以进行运算。
Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取余的操作。
将每一本书的价格提高100元:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import F def add_book(request): res = models.Book.objects.update(price=F("price")+100) print(res) return HttpResponse(res)
Q() 查询
使用前要先从 django.db.models 引入 Q:
from django.db.models import Q
用法:
Q(条件判断)
例如:
Q(title__startswith="入")
之前构造的过滤器里的多个条件的关系都是 and,如果需要执行更复杂的查询(例如 or 语句),就可以使用 Q 。
Q 对象可以使用 & | ~ (与 或 非)操作符进行组合。
优先级从高到低:~ & |。
可以混合使用 Q 对象和关键字参数,Q 对象和关键字参数是用"and"拼在一起的(即将逗号看成 and ),但是 Q 对象必须位于所有关键字参数的前面。
from django.db.models import Q
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import F,Q def add_book(request): res=models.Book.objects.filter(Q(price__gt=350)|Q(title__startswith="入")).values("title","price") print(res) return HttpResponse(res)
{'title': '入门教程', 'price': Decimal('300.00')}{'title': '入门教程', 'price': Decimal('300.00')}{'title': '入门教程', 'price': Decimal('300.00')}{'title': '入门教程', 'price': Decimal('300.00')}
查询以"入"结尾或者不是 2010 年 10 月份的书籍:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import F,Q def add_book(request): res = models.Book.objects.filter(Q(title__endswith="入") | ~Q(Q(pub_date__year=2010) & Q(pub_date__month=10))) print(res) return HttpResponse(res)
Book object (5)Book object (6)
查询出版日期是 2004 或者 1999 年,并且书名中包含有"入"的书籍。
Q 对象和关键字混合使用,Q 对象要在所有关键字的前面:
实例
from django.shortcuts import render, HttpResponse from app02 import models from django.db.models import F,Q def add_book(request): res = models.Book.objects.filter(Q(pub_date__year=2004) | Q(pub_date__year=1999), title__contains="入") print(res) return HttpResponse(res)
https://www.runoob.com/django/django-orm-3.html