zoukankan      html  css  js  c++  java
  • ORM聚合分组查询及优化

    1. 聚合查询

    Copy# 聚合函数: aggregate
    from django.db.models import Max,Min,Sum,Count,Avg
    # 统计所有书的最高价格
    res1 = models.Book.objects.all().aggregate(Max('price'))
    print(res1)     # {'price__max': Decimal('199.00')}
    # 统计所有书的最低价格
    res2 = models.Book.objects.all().aggregate(Min('price'))
    print(res2)     # {'price__min': Decimal('88.88')}
    # 统计所有书总价格
    res3 = models.Book.objects.all().aggregate(Sum('price'))
    print(res3)     # {'price__sum': Decimal('511.10')}
    # 统计所有书的数量
    res4 = models.Book.objects.all().aggregate(Count('price'))
    print(res4)     # {'price__count': 4}
    # 统计所有书平均价格
    res5 = models.Book.objects.all().aggregate(Avg('price'))
    print(res5)     # {'price__avg': 127.775}
    
    res6 = models.Book.objects.all().aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price'))
    print(res6)
    

    2. 分组查询:annotate

    Copy# 1.统计每一本书的作者个数
    res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num')
    print(res)     # <QuerySet [{'author_num': 1}, {'author_num': 0}, {'author_num': 2}, {'author_num': 0}]>
    
    # 2.统计出每个出版社卖的最便宜的书的价格
    res = models.Publish.objects.annotate(price_min = Min('book__price')).values('price_min')
    print(res)   # <QuerySet [{'price_min': Decimal('88.88')}, {'price_min': Decimal('99.99')}, {'price_min': Decimal('199.00')}]>
    
    # 3.统计不止一个作者的图书
    res = models.Book.objects.annotate(author_obj = Count('authors')).filter(author_obj__gt=1).values('title')
    print(res)     # <QuerySet [{'title': '西游记'}]>
    
    # 4.查询各个作者出的书的总价格
    res = models.Author.objects.annotate(price_sum = Sum('book__price')).values('price_sum')
    print(res)   # <QuerySet [{'price_sum': Decimal('212.11')}, {'price_sum': Decimal('88.88')}, {'price_sum': None}]>
    

    3. F与Q查询

    Copy"""
    F与Q查询
        我们之前在查询数据库的时候条件都是我们自己手写的
        但是现在出现了条件是从数据库里面获取的
    """
    from django.db.models import F,Q
    
    # F查询
    # 1.查询出卖出数大于库存数的书籍
    res = models.Book.objects.filter(maichu__gt=F('kucun'))
    print(res)   # <QuerySet [<Book: 三国演义>, <Book: 西游记>, <Book: 红楼梦>]>
    
    # 2.将所有的书的价格 全部提高100块
    models.Book.objects.update(price = F('price')+100)
    
    # 3.了解  尝试着将所有的书的名字后面都加上 爆款
    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.objects.update(title = Concat(F('title'),Value('爆款')))
    
    # Q查询
    # 1.查询书籍名称是西游记爆款或者价格是399的书
    res = models.Book.objects.filter(Q(title='西游记爆款')|Q(price=399))  # 用来Q之后 就能够支持|表示或
    print(res)     # <QuerySet [<Book: 西游记爆款>, <Book: 红楼梦爆款>]>
    res = models.Book.objects.filter(title='西游记爆款',price=399)   # 逗号就是and
    print(res)     # <QuerySet []>
    res = models.Book.objects.filter(~Q(title='西游记爆款') | Q(price=399))  # 波浪号  表示非
    print(res)     # <QuerySet [<Book: 三国演义爆款>, <Book: 水浒传爆款>, <Book: 红楼梦爆款>]>
    
    # Q查询进阶用法   用Q产生对象 然后再使用   
    # 字符串的左边 跟你的变量名条件书写一模一样
    q = Q()
    q.connector = 'or'   # 或
    q.children.append(('title__icontains','p'))
    q.children.append(('kucun',100))
    res = models.Book.objects.filter(q)
    print(res)     # <QuerySet [<Book: p三国演义爆款>, <Book: P水浒传爆款>, <Book: 西游记爆款>]>
    

    4. orm中常见字段

    CopyAutoField(primary_key=True)
    # int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列
    
    CharField(max_length=32)   # varchar(32)
    # 字符类型,必须提供max_length参数, max_length表示字符长度
    
    IntegerField()    # int
    # 一个整数类型,范围在 -2147483648 to 2147483647 (一般不用它来存手机号(位数也不够),直接用字符串存)
    
    BigIntegerField()    # long
    # 长整型
    
    DateField()
    # 日期字段,日期格式  YYYY-MM-DD
        # auto_now:每次修改数据的时候 都会更新该字段
        # auto_now_add:只在创建数据的时候 才会自动将创建时间添加 后续不会再自动修改了
            
    DecimalField()
    # 浮点型
    
    BooleanField(Field)
    # 布尔值类型
        # 该字段在存储数据的时候 你只需要传布尔值即可
        # 对应到数据库中 会变成0/1
        
    TextField(Field)
    # 文本类型 存大段文本
    
    EmailField(CharField)    # varchar(...)
    # 邮件类型
    
    FileField(Field)
    # 字符串,路径保存在数据库,文件上传到指定目录
    # 参数:
        # upload_to = ""      上传文件的保存路径
        # storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
    
    DecimalField(Field)
    # 10进制小数
    # 参数:
        # max_digits,小数总长度
        # decimal_places,小数位长度
    

    5. 自定义char字段

    Copyclass MyCharField(models.Field):
        def __init__(self,max_length,*args,**kwargs):
            self.max_length = max_length
            super().__init__(max_length=max_length,*args,**kwargs)
        def db_type(self, connection):
            return 'char(%s)'%self.max_length
        
    '''
    注:如果你使用的是django2.X版本 你在建数据库表关系的时候
    你需要手动指定两个参数: 
    on_delete  db_constraint
    (级联更新 级联删除  是否建外键约束)
    '''
    

    6. 查询优化

    Copy# 惰性查询
    # only()
    res = models.Book.objects.all()
    print(res)   # <QuerySet [<Book: p三国演义爆款>, <Book: P水浒传爆款>, <Book: 西游记爆款>, <Book: 红楼梦爆款>]>
    res = models.Book.objects.values('title')
    print(res)   # <QuerySet [{'title': 'p三国演义爆款'}, {'title': 'P水浒传爆款'}, {'title': '西游记爆款'}, {'title': '红楼梦爆款'}]>
    res = models.Book.objects.only('title')
    # print(res)   # <QuerySet [<Book: p三国演义爆款>, <Book: P水浒传爆款>, <Book: 西游记爆款>, <Book: 红楼梦爆款>]>
    for r in res:
        print(r.title)
        print(r.price)
    '''
    only会将括号内的字段对应的值 直接封装到返回给你的对象中  点该字段 不需要再走数据库
    一旦你点了不是括号内的字段  就会频繁的去走数据库查询
    '''
    
    
    # defer()    defer和only互为反关系
    res = models.Book.objects.defer('title')
    for r in res:
        print(r.title)
        print(r.price)
    """
    defer会将括号内的字段排除之外将其他字段对应的值 直接封装到返回给你的对象中  点该其他字段 不需要再走数据库
    一旦你点了括号内的字段  就会频繁的去走数据库查询
    """
    
    
    # select_related: 表之间进行join连表操作,一次性获取关联的数据
    res = models.Book.objects.select_related('publish')
    print(res)   # <QuerySet [<Book: p三国演义爆款>, <Book: P水浒传爆款>, <Book: 西游记爆款>, <Book: 红楼梦爆款>]>
    for r in res:
        print(r.publish)
        print(r.publish_date)
    
    res1 = models.Author.objects.select_related('author_detail')
    print(res1)   # <QuerySet [<Author: aa>, <Author: zz>, <Author: qq>]>
    for r1 in res1:
        print(r1.author_detail)
        print(r1.author_detail.phone)
        print(r1.author_detail.addr)
    """
    select_related 会自动帮你做连表操作 然后将连表之后的数据全部查询出来封装给对象
    
    select_related括号内只能放外键字段
        并且多对多字段不能放
    
    如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
            select_related(外键字段__外键字段__外键字段...)
    
    """
    
    
    # prefetch_related: 多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作
    res = models.Book.objects.prefetch_related('publish')
    print(res)   # <QuerySet [<Book: p三国演义爆款>, <Book: P水浒传爆款>, <Book: 西游记爆款>, <Book: 红楼梦爆款>]>
    for r in res:
        print(r.publish.name)
    """
    prefetch_related  看似连表操作  其实是类似于子查询
    prefetch_related括号内只能放外键字段
        并且多对多字段不能放
    
    如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
            select_related(外键字段__外键字段__外键字段...)
    """
    
    
    """
    select_related 内部自动连表 消耗的资源就在连表上   但是走数据库的次数较少
    
    prefetch_related 内部不做连表 消耗的资源就在查询次数上  但是给用户的感觉跟连表操作一样
    """
    

    7. django如何开启事务

    Copy# 事务的四大特性:ACID
    # 原子性  一致性  隔离性  持久性
    
    # commit  rollback
    # 要么同时成功要么同时失败
    
    # django中如何开启事务
    from django.db import transaction
    with transaction.atomic():
        # 在该代码块中所写的orm语句 同属于一个事务
        pass
    
    # 缩进出来之后自动结束
    
  • 相关阅读:
    Android常用URI收藏
    2017 ZSTU寒假排位赛 #3
    HDU 3689 Infinite monkey theorem ——(自动机+DP)
    CodeForces 755D PolandBall and Polygon ——(xjbg)
    2017 ZSTU寒假排位赛 #2
    HDU 3264 Open-air shopping malls ——(二分+圆交)
    HDU 1255 覆盖的面积 ——(线段树+扫描线)
    HDU 3265 Posters ——(线段树+扫描线)
    2017 ZSTU寒假排位赛 #1
    UVA 11853 Paintball ——(dfs+圆交判定)
  • 原文地址:https://www.cnblogs.com/oxtime/p/11755343.html
Copyright © 2011-2022 走看看