今日内容概要
-
max、min、sum、count、avg
-
分组查询(group by的使用)annotate
-
F与Q查询
-
django中如何开启事务
-
orm中常用字段及参数
-
数据库查询优化(only与defer、select_related与prefetch_related)
-
"""
聚合查询通常情况下都是配合分组一起使用的,只要是跟数据库相关的模块 ,基本上都在django.db.models里面,如果上述没有那么应该在django.db里面
"""
#聚合查询 aggregate from django.db.models import Max,Min,Sum,Avg,Count #所有书的平均价格 res = models.Book.objects.aggregate(Avg('price')) # print(res) res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('pk'), Avg('price')) print(res)
分组查询
# 分组查询 annotate # 1.统计每一本书的作者个数 res = models.Book.objects.annotate(author_num = Count('author')).values('title','author_num') print(res) #2.正常情况下应该是需要在Count内部的author后面加上__id,因为是反向查询,需要跨表到作者表中去查个数,如下所示,但是orm自动简化,只需要写author即可 res = models.Book.objects.annotate(author_num = Count('author__id')).values('title','author_num') print(res) #统计每个出版社卖的最便宜的书的价格 res = models.Publish.objects.annotate(min_price = Min('book__price')).values('name','min_price') print(res) # 3.统计不止一个作者的图书 # """ # 只要你的orm语句得出的结果还是一个queryset对象 # 那么它就可以继续无限制的点queryset对象封装的方法 # """ res = models.Book.objects.annotate(author_num = Count('author')).filter(author_num__gt=1).values('title','author_num') print(res) # 4.查询每个作者出的书的总价格 res = models.Author.objects.annotate(price_sum = Sum('book__price')).values('name','price_sum') print(res) #补充几个额外的知识点: #1.如果我想按照指定的字段分组该如何处理呢? # models.Book.objects.values('price').annotate() 先将要指定的字段拿出来,再进行分组 #2.你们的机器上如果出现分组查询报错的情况怎么办?你需要修改数据库严格模式
F与Q查询
# F查询 """ 能够帮助你直接获取到表中某个字段对应的数据 """ #1.查询卖出数大于库存数的书籍 from django.db.models import F # #不需要查询两次,先查询书籍的卖出数,再查询库存数,然年后将两者进行比较。利用F查询可以直接将要查询的字段的数据拿出 # res = models.Book.objects.filter(maichu__gt=F('kucun')) # print(res) # 2.将所有书籍的价格提升100块 res = models.Book.objects.update(price = F('price')+100) # 3.将所有书的名称后面加上爆款两个字 """ 在操作字符类型的数据的时候 F不能够直接做到字符串的拼接 """ from django.db.models.functions import Concat from django.db.models import Value #利用Concat和Value完成字符串的拼接 models.Book.objects.update(title = Concat(F('title'),Value('爆款'))) # models.Book.objects.update(title=F('title') + '爆款') # 所有的名称会全部变成空白
#Q查询 from django.db.models import Q #(与 ,) (或 |) (非 ~) #1.查询卖出数大于100或者价格小于600的书籍 #res = models.Book.objects.filter(maichu__gt=100,price__lt=600) 无法查询,因为filter后参数还是and关系 # # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600))#Q包裹逗号分割 还是and关系 # res = models.Book.objects.filter(Q(maichu__gt=100) | Q(price__lt=600)) # | or关系 # res = models.Book.objects.filter(~Q(maichu__gt=100) | Q(price__lt=600)) # ~ not关系 # Q的高阶用法 能够将查询条件的左边也变成字符串的形式 q = Q() q.connector = 'or' q.children.append(('maichu__gt', 100)) q.children.append(('price__lt', 600)) res = models.Book.objects.filter(q) # 默认还是and关系 print(res)
django中如何开启事务
首先复习一下mysql中事物的四大特性:ACID A:原子性 C:一致性 I:隔离性 D:持久性 事物的回滚:roolback 事物的确认:commit,目前我们只需要学习如何在django中开启事务
from django.db import transaction try: with transaction.atomic(): #sql1 ... #sql2 except Exception as e: print(e) print('执行其他操作')
ORM中常用的字段及参数
AutoField 主键字段 primary_key=True CharField varchar verbose_name 字段的注释
max_length 长度
IntegerField int BigIntegerField bigint DecimalField max_digits=8 decimal_places=2 EmailFiled varchar(254) DateField date DateTimeField datetime auto_now:每次修改数据的时候都会自动更新当前时间 auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了 BooleanField(Field) - 布尔值类型 该字段传布尔值(False/True) 数据库里面存0/1 TextField(Field) - 文本类型 该字段可以用来存大段内容(文章、博客...) 没有字数限制 后面的bbs作业 文章字段用的就是TextField FileField(Field) - 字符类型 upload_to = "/data" 给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中(/data/a.txt) 后面bbs作业也会涉及 # 更多字段 直接参考博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
django中自定义字段:
class My_field(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length # 调用父类的init方法 super().__init__(max_length=max_length,*args,**kwargs)# 调用父类的init方法 def db_type(self, connection): return 'char(%s)' % self.max_length
# 外键字段及参数
unique=True
ForeignKey(unique=True) === OneToOneField()
# 你在用前面字段创建一对一 orm会有一个提示信息 orm推荐你使用后者但是前者也能用
db_index
如果db_index=True 则代表着为此字段设置索引
(复习索引是什么)
to_field
设置要关联的表的字段 默认不写关联的就是另外一张的主键字段
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
"""
django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除
"""
数据库查询优化
only与defer
select_related与prefetch_related
"""
orm语句的特点:
惰性查询
如果你仅仅只是书写了orm语句 在后面根本没有用到该语句所查询出来的参数
那么orm会自动识别 直接不执行
"""
# only与defer # res = models.Book.objects.all() # print(res) # 要用数据了才会走数据库 # 想要获取书籍表中所有数的名字 # res = models.Book.objects.values('title') # for d in res: # print(d.get('title')) # 你给我实现获取到的是一个数据对象 然后点title就能够拿到书名 并且没有其他字段 # res = models.Book.objects.only('title') # res = models.Book.objects.all() # print(res) # <QuerySet [<Book: 三国演义爆款>, <Book: 红楼梦爆款>, <Book: 论语爆款>, <Book: 聊斋爆款>, <Book: 老子爆款>]> # for i in res: # print(i.title) # 点击only括号内的字段 不会走数据库 # print(i.price) # 点击only括号内没有的字段 会重新走数据库查询而all不需要走了 res = models.Book.objects.defer('title') # 对象除了没有title属性之外其他的都有 for i in res: print(i.price) """ defer与only刚好相反 defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据 而如果查询的是非括号内的字段 则不需要走数据库了 """ # select_related与prefetch_related # select_related与prefetch_related 跟跨表操作有关 # res = models.Book.objects.all() # for i in res: # print(i.publish.name) # 每循环一次就要走一次数据库查询 # res = models.Book.objects.select_related('authors') # INNER JOIN """ select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据 全部封装给查询出来的对象 这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了 select_related括号内只能放外键字段,只在一对多、一对一时候使用,多对多时不行。 使用方式:selected_related(外键字段1__外键字段2__外键字段3__...) """ # for i in res: # print(i.publish.name) # 每循环一次就要走一次数据库查询 res = models.Book.objects.prefetch_related('publish') # 子查询 """ prefetch_related该方法内部其实就是子查询 将子查询查询出来的所有结果也给你封装到对象中 给你的感觉好像也是一次性搞定的 """ for i in res: print(i.publish.name)