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

# 缩进出来之后自动结束

猜你喜欢

转载自www.cnblogs.com/oxtime/p/11755343.html