聚合,咱们应该有这个概念,由于在数据库的SQL语言里面有聚合函数的概念,聚合,字面意思来讲,就是把一类东西放在一块儿,可是跟分组又不太同样.python
咱们知道咱们在写SQL语句的时候,分组groupby和聚合函数是分不开的,由于一旦select语句里面有分组,那么咱们就只能查询到分组依据的字段以及一些聚合函数组成的字段,别的字段写在select后面会报错的.git
因此,既然ORM是用来操做数据库的,那么咱们在使用聚合查询的时候,就要遵循这个规律.聚合查询的具体用法以下:数据库
# 首先导入聚合函数,聚合函数的关键字为aggregate from django.db.models import Max,Min,Sum,Count,Avg # 大概格式为:models.表名.objects.查询方式(匹配条件).aggregate(聚合函数(表中的字段)) res = models.Book.objects.all().aggregate(Avg('price')) print(res)
分组查询的关键字为annotate,使用起来很是的简单,实际在数据库里的操做其实就是groupby,分组查询会按照models后面的表名来分组,而后在后面括号内对分组后的数据进行操做django
# 分组查询的格式为:models.表名.objects.annotate(对组内数据作操做) res = models.Book.objects.annotate(author_number=Count('authors').values('author_num')) print(res)
上面的聚合和分组查询都是咱们从表中取出字段,而后与一个咱们设定好的常量做比较,设想这样一种情景,若是咱们须要从数据库取出来两个不一样字段的值做比较,该如何实现呢?Django里面就给咱们提供了F和Q查询来解决这一问题.后端
from django.db.models import F,Q res = models.Book.objects.filter(sell = F('kucun')) print(res) # 以上语句能够实如今Book表中,咱们以kucun列为依据,来查询获得本身想要的数据,甚至能够在查询的时候直接对数据作操做,好比 res = models.Book.objects.filter(sell = F('kucun')+100) print(res) # 而Q查询比F查询更增强大,好比如下情景 # 咱们须要根据不止一个条件来筛选记录,并且这些条件并非and关系,而是or,或者not,此时就可使用Q查询来解决问题,好比: res = models.Book.objects.filter(Q(title='python')|Q(kucun=666)) res1 = models.Book.objects.filter(~Q(title='python')|Q(kucun=666)) print(res,res1) # 以上两个例子,在两个Q之间用|是or的意思,即二者只要有一个成立就算符合条件,~则是取反的意思
Q查询还有一种更优秀的用法,咱们知道Q查询实际上是一个类,因此咱们经过实例化产生一个对象,而后经过操做这个对象来实现Q查询以及对数据进行筛选的目的,好比数组
from django.db.models import Q q = Q() q.connector = 'or' # 这里能够直接配置其查询的方式,能够是or,能够是not q.children.append(('title','python')) q.children.append(('kucun',666)) res = models.Book.objects.filter(q) print(res)
ORM的查询优化通常会有四个比较经常使用的方法,他们都是成对出现,对比使用的,即only和defer,select_relater和prefetch_related,下面咱们逐一介绍.缓存
only和defer('字段') 首先他们的用法都是在关键字后面括号中加入表中有的字段. only会将括号内字段对应的全部数据直接封装起来,而后返回给咱们的对象中,由于only()最后返回的是一个对象,而后咱们对这个对象来进行操做的时候,若是点出来的是以前括号内的字段,那么这次查询就不会再通过数据库,可是若是点出来是括号内不包含的字段,那么每次都会从新查询数据库. 作一个类比来讲,only后面括号内字段所对应的数据至关因而拿出来放在了计算机的缓存中,咱们在查询这个字段的时候就直接从缓存里取,而不须要再去查询数据库,能够节约大量查询的时间,固然这只是一个类比,实际状况并非缓存的概念. defer的用法就和only彻底相反,defer后面括号内字段对应的数据,在每次查询的时候都须要查询数据库,而括号内不包含的字段对应的数据查询则不须要查询数据库. 我的理解only和defer的用法,only应该是用在不常修改的字段,也就是说only后面括号内的字段应该是修改次数尽可能少的字段,这样既能提高效率,查询出来又不会出错.同理,defer后面括号内则是应该写频繁修改的字段,须要实时监控其变化的那种字段,比较合适.
select_relater和prefetch_related('外键关联表的表名') 首先,select_relater和prefetch_related的共同点在于其传参的规则是相同的,其后面的括号里面都只能放外键字段,且只能放一对一和一对多的外键字段,不能放多对多的字段,并且能够叠加,便可以select_related(外键字段__外键字段__外键字段)这样放. select_related会自动帮咱们作连表操做,这些表必须是有外键相关联的,select_related将连表以后的数据所有查询出来,而后封装起来,传给对象. 而prefetch_related看似也是一个连表操做,其实不是,prefetch_related其实是一种相似子查询的存在,其会屡次查询不一样的表,而后把最后的结果返回出来. 这两种方法的区别在于 第一种,内部自动连表,消耗的资源和时间都在连表上,对数据库的操做比较少,数据库压力小 第二种,内部不作连表,消耗的资源和时间都在对数据库的查询上,数据库压力较大,可是总体效率较高
ORM中的字段就是咱们在models.py里面定义表类型的时候,对于字段的定义所用的格式,经常使用的有如下几种:markdown
# 自增的数字,经常使用来设置主键,primary_key = True就为主键 AutoField(primary_key = True) # 最经常使用的字符类型,至关于python中的varchar,max_length为其最大长度,超过这个长度的会被舍弃 CharField(max_length=32) # 整型,默认括号内为空 IntegerField() # 时间格式,经常使用参数有两个: DateField() auto_now:每次对对象进行操做都会更新当前时间 auto_now_add:在建立或添加对象的时候会添加这个时间,而后不会改变 # 小数格式的数字,max_digits为数字的总位数,decimal_places为数字的小数的位数 DecimalField(max_digits=8,decimal_places=2) # 布尔类型,存储到数据库中的时候是0/1,并非True和False BooleanField()
choices参数一般是IntegerField中的参数,由于咱们市场但愿的是用简单的数字来代替不一样的意思,或者选项,好比咱们在定义一个类中字段的是时候,该字段要显示用户的性别,咱们能够这么写:app
# models.py choices = ( (1,'male'), (2,'female'), (3,'guess') ) sex = models.IntegerField(choices=choices) # 以上这种操做就能够实现咱们的需求,在后端向前端传送数据的时候只须要传1,2,3就能够了,大大减小了传送数据的量级
这种使用方式能够简化传送数据的大小,可是在取数据的时候也和原来有些区别,并非直接用点的形式来取数据了.
from app01 import models user_obj = models.Userinfo.objects.filter(pk=1),first() res = user_obj.get_gender_display() print(res) # 其取值方式为固定句式,即 # 数据对象.get_字段名_display() # 注意,若是数字没有对应关系的话,该种方式取出来的仍是这个数字,并不会报错
咱们知道数据库中有事务,事务的四大特色ACID为
原子性
一致性
隔离性
持久性
因此咱们在ORM中也须要有事务的存在.具体操做以下
from django.db import transaction with transaction.atomic() #这里写的全部ORM语句都属于同一个事务 # 事务的结束标志就是这一个缩进