• Django(10)ORM聚合查询



    此文章参考菜鸟教程:Django ORM – 多表实例(聚合与分组查询) | 菜鸟教程 (runoob.com)

    Django版本:

    >>> django.VERSION  
    (4, 1, 0, 'final', 0)
    
    • 1
    • 2

    PS:基于前几章的进度进行修改

    一、聚合查询—aggregate()

    • 聚合查询函数是对一组值执行计算,并且返回单个值
    • Django使用聚合查询之前需要先从django.db.models引入Avg,Max,Min,Count,Sum,注意需要首字母大写
    from django.db.models import Avg,Max,Min,Count,Sum
    
    • 1

    Avg:计算平均值

    Max:最大值

    Min:最小值

    Count:统计出现的次数

    Sum:和

    • 聚合查询返回的值的数据类型是字典,而聚合函数aggregate()是QuerySet的一个终止子句,生成的一个汇总值,相当于count()函数。需要注意的是,使用aggregate()后,数据类型就变成了字典类型,不能再使用QuerySet数据类型的一些API了
    • 日期数据类型DateField可以使用MaxMin
    • 返回的字典中,键的名称默认是属性名称+__聚合函数名称,值是计算出来的聚合值,如果要自定义返回字典的键的名称,可以起别名,例如:
    aggregate(别名 = 聚合函数名("属性名称"))
    
    • 1
    • 实例,计算所有图书的平均价格
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.aggregate(Avg("price"))
        print(res,type(res))
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 访问127.0.0.1:8000/add_book进行测试,观察终端输出,可以看到输出数据类型是字典

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 计算所有图书的数量,价格的最大值和最小值
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.aggregate(c=Count("id"),max=Max("price"),min=Min("price"))
        print(res,type(res))
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    二、分组查询—annotate()

    • 分组查询同样也会用到聚合函数,同样先从django.db.models引入Avg,Max,Min,Count,Sum,注意需要首字母大写
    from django.db.models import Avg,Max,Min,Count,Sum
    
    • 1
    • 返回值:

    分组后使用values取值,返回值是QuerySet数据类型里面的一个个字典

    如果使用Values_list取值,那么返回值则是QuerySet数据类型里的一个个元组

    • Mysql中的limit就相当于ORM中QuerySet数据类型的切片

    • 注意:

    annotate里面存放聚合函数,其中:

    1. values或values_list放在annotate前面:前面的values或values_list声明以什么字段分组,是字典还是元组,而annotate执行分组
    2. values或values_list放在annotate后面:annotate表示直接以当前表的pk(主键)执行分组,后面的values或values_list表示查询哪些字段,==(也就是输出什么字段)==并且要将annotate里面的聚合函数起别名,在values或values_list中写它的别名
    • 准备数据和创建模型
    - models.py
    # -*- coding: utf-8 -*-
    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=32)		
        price = models.DecimalField(max_digits=5,decimal_places=2)	
        pub_date = models.DateField()
        publish = models.ForeignKey("Publish",on_delete=models.CASCADE)  #多对一
        authors = models.ManyToManyField("Author")  #多对多
    
    class Publish(models.Model):
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=64)
        email = models.EmailField()
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        age = models.SmallIntegerField()
        au_detail = models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)  #一对一
    
    class AuthorDetail(models.Model):
        gender_choices = (
            (0,"女"),
            (1,"男"),
            (2,"保密"),
        )
        gender = models.SmallIntegerField(choices=gender_choices)
        tel = models.CharField(max_length=32)
        addr = models.CharField(max_length=64)
        birthday = models.DateField()
    
    class Emp(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        salary = models.DecimalField(max_digits=8, decimal_places=2)
        dep = models.CharField(max_length=32)
        province = models.CharField(max_length=32)
    
    class Emps(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        salary =     models.DecimalField(max_digits=8, decimal_places=2)
        dep = models.ForeignKey("Dep", on_delete=models.CASCADE)
        province = models.CharField(max_length=32)
        
    class Dep(models.Model):
        title = models.CharField(max_length=32)
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 更新数据表
    (test) PS F:\django\app1> python .\manage.py makemigrations app1_model
    Migrations for 'app1_model':
      app1_model\migrations\0003_dep_emp_emps_remove_book_authors_remove_book_publish_and_more.py
        - Create model Dep
        - Create model Emp
        - Create model Emps
        - Remove field authors from book
        - Remove field publish from book
        - Delete model Author
        - Delete model AuthorDetail
        - Delete model Book
        - Delete model Publish
    (test) PS F:\django\app1> python .\manage.py migrate app1_model
    Operations to perform:
      Apply all migrations: app1_model
    Running migrations:
      Applying app1_model.0003_dep_emp_emps_remove_book_authors_remove_book_publish_and_more... OK
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 查看数据库,确认之前的表删除,刚刚新的表创建

    在这里插入图片描述

    • 新建查询,写入

    在这里插入图片描述

    INSERT INTO app1_model_emp (id,name,age,salary,dep,province) VALUES ('1','令狐冲','24','6000.00','销售部','河南'); 
    INSERT INTO app1_model_emp (id,name,age,salary,dep,province) VALUES ('2','任盈盈','18','8000.00','关公部','广东'); 
    INSERT INTO app1_model_emp (id,name,age,salary,dep,province) VALUES ('3','任我行','56','10000.00','销售部','广东'); 
    INSERT INTO app1_model_emp (id,name,age,salary,dep,province) VALUES ('4','岳灵珊','19','6000.00','关公部','河南'); 
    INSERT INTO app1_model_emp (id,name,age,salary,dep,province) VALUES ('5','小龙女','20','8000.00','关公部','河北'); 
    INSERT INTO app1_model_dep (id,title) VALUES ('1','销售部'); 
    INSERT INTO app1_model_dep (id,title) VALUES ('2','关公部'); 
    INSERT INTO app1_model_emps (id,name,age,salary,province,dep_id) VALUES ('2','令狐冲','24','8000.00','河南','1'); 
    INSERT INTO app1_model_emps (id,name,age,salary,province,dep_id) VALUES ('3','任盈盈','18','9000.00','广东','2'); 
    INSERT INTO app1_model_emps (id,name,age,salary,province,dep_id) VALUES ('4','任我行','57','10000.00','广东','1');
    INSERT INTO app1_model_emps (id,name,age,salary,province,dep_id) VALUES ('5','岳灵珊','19','6000.00','河南','2');
    INSERT INTO app1_model_emps (id,name,age,salary,province,dep_id) VALUES ('6','小龙女','20','8000.00','河北','2');
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    • 查看数据库信息

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    • 下面统计每一个出版社的最便宜的书的价格
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Publish.objects.values("name").annotate(in_price = Min("book__price"))
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    • 统计每一本书的作者个数
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.annotate(c = Count("authors__name")).values("title","c")  
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出
      在这里插入图片描述

    在这里插入图片描述

    • 统计每一本以Python开头的书籍的作者个数
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.filter(title__startswith="Python").annotate(c = Count("authors__name")).values("title","c")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述
    在这里插入图片描述

    • 统计不止一个作者的图书名称
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.annotate(c = Count("authors__name")).filter(c__gt=0).values("title","c")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    • 根据一本图书作者数量的多少对查询集QuerySet进行降序排序
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.annotate(c = Count("authors__name")).order_by("-c").values("title","c")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    • 查询各个作者出的书的总价格
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Author.objects.annotate(all=Sum("book__price")).values("name","all")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述
    在这里插入图片描述

    三、F()查询

    • F()的实例可以在查询中引用字段,来比较同一个model实例中两个不同字段的值,之前的过滤器都只是将字段值与某个常量作比较,如果想要对两个字段的值进行比较,就需要用到F()
    • 使用前需要先从django.db.models引入F:
    from django.db.models import Avg,Max,Min,Count,Sum,F
    
    • 1
    • 语法:F("字段名称")

    • F()动态获取对象字段的值,可以进行运算,Django支持F()对象之间以及F()对象和常数之间的加减乘除和取余的操作,修改操作即update也可以使用F()函数

    • 查询工资大于年龄的人

    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum,F
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        book = models.Emp.objects.filter(salary__gt=F("age")).values("name","age")
        print(book)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    • 将每一本书的价格提高100元
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum,F
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.update(price=F("price")+100)
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看数据库信息,可以看到成功修改价格
      在这里插入图片描述

    在这里插入图片描述

    四、Q()查询

    • 使用前需要在django.db.models中引入Q:
    from django.db.models import Avg,Max,Min,Count,Sum,F,Q
    
    • 1
    • 用法:Q(条件判断),例如
    Q(title__startswith="Python")
    
    • 1
    • 之前构造的过滤器里的多个条件的关系都是and,如果需要执行更复杂的查询,例如or语句,就可以使用Q()

    • Q对象可以使用&,|,~,即与、或、非等操作符进行组合,优先级从高到低为~ & |,可以混合使用Q对象和关键字参数,Q对象和关键字参数是使用and拼在一起的,即把,看成的关系,但是Q对象必须位于所有关键字参数的前面

    • 查询价格大于350或者名称以Python开头的书籍和名称和价格

    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum,F,Q
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.filter(Q(price__gt=350)|Q(title__startswith="Python")).values("title","price")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    • 查询以M教程结尾或者不是2011年11月的书籍
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum,F,Q
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.filter(Q(title__endswith="M教程")|~Q(Q(pub_date__year=2011) & Q(pub_date__month=11))).values("title","pub_date")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出

    在这里插入图片描述

    在这里插入图片描述

    • 查询出版日期是2011年11月的或者2012年10月的,并且名称中包含教程
    # -*- coding: utf-8 -*-
    from django.shortcuts import render,HttpResponse
    from app1_model import models
    from django.db.models import Avg,Max,Min,Count,Sum,F,Q
    
    def add_book(request):
        #books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")  
        res = models.Book.objects.filter(Q(pub_date__year=2011) & Q(pub_date__month=11),Q(title__contains="教程")).values("title","pub_date")
        print(res)
        return HttpResponse("ok")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 访问测试,查看终端输出
      在这里插入图片描述
      在这里插入图片描述
  • 相关阅读:
    VUE快速入门-5
    计算机毕业设计:基于HTML学校后台用户登录界面模板源码
    7.JavaScript-vue
    【简单讲解下epoll】
    Markdown格式表情包大全最新整理分享
    【Python脚本进阶】1.3、第一个脚本:UNIX口令破解机
    一切测试的基础——测试用例设计
    TensorFlow入门(十九、softmax算法处理分类问题)
    【数据处理必备Numpy~python】
    手把手教你Prometheus + Granafa实现mysql 性能监测部署
  • 原文地址:https://blog.csdn.net/rzy1248873545/article/details/127609435