djangoORM
正反向查询进阶操作
查询主键为3的书籍对应的出版社名称以及书名
查询主键为4的书籍对应的作者姓名及书名
查询老舍的作者的电话号码和地址
查询上海出版社出版的书籍名称和价格
查询jason写过的书的名称和日期
查询电话是1188的作者姓名和年龄
查询主键为6的书籍对应的作者和对应电话号码
聚合查询
聚合函数主要有:max
,min
,sum
,avg
,count
使用这些函数前需要从`django.db.models模块中导入对应的类:
from django.db.models import Max,Min,Sum,Avg,Count
没有分组之前如果单纯的想要使用聚合函数,则需要关键字aggregate
分组查询
分组之前设置了一个特性only_full_group_by
特性,该特性为只能够直接获取分组的字段,其他字段需要使用方法,我们也可以忽略掉该特性。将sql_mode中only_full_group_by
配置移除即可。
分组查询
按照整条数据分组
models.Book.objects.annotate() # 按照一条条数据记录分组
按照表中某个字段分组
models.Book.objects.value('title').annotate() 按照annotate之前values括号中指定的字段分组
统计每一本书的作者个数
统计出每个出版社卖的最便宜的书的价格
统计不止一个作者的图书
注意filter
在annotate
前面则是where,在annotate后面是having
查询各个作者出的书的总价格
F与Q查询
F查询
Django中提供F(),当两个字段的值做比较的时候,F()的实例可以在查询中引用字段,来比较同一个model实例中两个不同字段的值。
查询库存数大于卖出数的书籍
F可以帮我们取到表中某个字段对应的值来作为筛选条件,而不是自定义常量的条件,实现了动态比较的效果。
将所有书籍的价格上涨了100
Django支持F()对象之间以及F()对象和常熟之间的加减乘除和取模的操作。基于此可以对表中的数值类型进行数学运算。
models.Book.objects.Update(price=F('price')+100)
将所有书籍名称加上爆款后缀
如果要修改char字段的话,需要导入Concat
、Value
两个类
Concat表示进行字符串的拼接操作,参数位置决定了拼接是在头部拼接还是尾部拼接,Value里面是要新增的拼接值。
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.filter(pk=5).update(title=Concat('title',Value('爆款')))
Q查询
filter()
等方法中逗号隔开的条件是与的关系。如果你需要执行更复杂的查询,可使用Q对象
查询卖出数大于600或者价格小于300块的书籍
对条件包裹一层Q的时候,filter即可支持交叉并的比较符
from django.db.models import Q
res = models.Book.objects.filter(Q(stock_num__gt=600)|Q(price__lt=300))
查询库存数是10000,并且卖出去不是0的数据
我们可以用组合&和|操作符以及使用括号进行分组来编写任意复杂的Q对象。同时,Q对象可以使用~操作符取反,这允许组合正常的查询和取反(not)查询。
from django.db.models import Q
models.Book.objects.filter(Q(stock_num=10000)&~Q(sale_num=0))
查询产品名包含新款,并且库存数大于900的书籍
查询函数可以混合使用Q对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q对象)都将AND
在一起。但是,如果出现Q对象,它必须位于所有关键字参数的前面。
models.Book.objects.filter(Q(stock_num__gt=900),title__contains='爆款')
Q查询,还可以将查询条件的字段改为字符串形式
q_obj=Q()
q_obj.connector='or' # q对象默认的多个条件也是and关系,可以修改为or
q_obj.children.append(('pk',1))
q_obj.children.append(('publish_id',2))
res=models.Book.object.filter(q_obj)
ORM查询优化
- django orm默认都是惰性查询,当orm的语句在后续的代码中真正需要使用的时候才会执行
- django orm自带limit分页,减轻数据库以及服务端的压力
only与defer
only
res=models.Book.objects.only('title','price')
for obj in res:
print(obj.title)
# print(obj.publish_time)
only会将括号内填写的字段封装成一个个数据对象,缓存在内存中,对象在点击的时候不会再走数据库查询,直接从内存中拿。但是对象也可以点击括号内没有的字段,只不过每次都会走数据库查询。
defer
res=models.Book.objects.defer('title','price')
for obj in res:
# print(obj.title)
print(obj.publish_time)
defer与only刚好相反,数据对象点击考好内出现的字段,每次都会走数据库查询;数据对象点击括号内没有的字段,不会走数据库查询
select_related与prefetch_related
select_related===>连表查询
select_related括号内只能接受外键字段(一对多,一对一)自动连表,得出的数据对象在点击表中数据的时候都不会再走数据库查询,因为第一次查询已经将整个表缓存到内存中。
res=models.Book.objects.select_related('publish')
for obj in res:
print(obj.publish)
print(obj.publish.name)
prefetch_related===>子查询
底层其实是子查询,将查询之后的结果也一次性封装到数据对象中,用户在使用的时候感觉不出来的
res=models.Book.objects.prefetch_related('authors')
for obj in res:
print(obj.title)
print(obj.authors.all())
总结
一对多、一对一情况下使用selected_related
;多对多情况下使用prefetch_related
。
ORM事务操作
事务操作
- A:原子性
- C:一致性
- I:隔离性
- D:持久性
事务隔离级别
- 脏读
- 幻读
- 可重复读
- 可串行读
原生sql事务语法
start transaction
rollback
commit
savepoint
django中开启事务
from django.db import transaction
try:
with transaction.atomic();
# 多条ORM语句
except Exception as e:
# 执行事务失败后的操作
# rollback
模型层常见字段
AutoField() int自增列,必须填入参数primary_key=True。当model中如果没有自增列,则自动创建一个列表名为id的列。
IntergerField() 一个整数类型,范围在-2147483648 to 2147483647 一般不用它来存手机号(位数也不够),直接用字符串存
BigIntegerField()
CharField() 字符类型,必须提供max_length参数,max_length表示字符长度
DateField() 时间类型,有两个参数:auto_now,auto_now_add
DateTimeField() 时间类型,有两个参数:auto_now,auto_now_add
DecimalField() 小数,有两个参数:max_degits,decimal_places
EmailField()
BooleanField() 传布尔值,存0或1
TextField() 传大段文本
FileField() 存储文件数据,自动找执行位置存储,字段存具体路径
ForeignKey()
OneToOneField()
ManyToManyField()
ORM自定义字段
django没有设置对应的char类型的字段,但是django允许我们自定义新的字段,下面为自定义对应于数据库的char类型。
from django .db.models import Field
class MyChar(Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length=max_length
super().__init__(max_length=max_length,*args,**kwargs)
def tb_type(self,connection):
"""
限定生成的数据表字段类型char,长度为max_length指定的值
:param connection:
:return:
"""
return f'char({self.max_length})'
自定义字段在实际项目应用中可能会经常用到,我们需要有个印象。
ORM常见字段参数
max_length 字符长度
ver_bose_name 注释
auto_now 创建时间,每次修改row都会跟着修改
auto_now_add 创建时间后都不会自动修改
null 表示某个字段可以为空
default 设置默认值
max_digits 小数的总位数
decimal_places 小数的位数
unique=True 设置唯一
db_index=True 设置索引
to 设置要关联的表
to_field 设置要关联的表的字段
choices
当字段数据的可能性是可以完全列举出来的时候,应该考虑使用该参数
class UserInfo(models.Model):
name CharField(max_length=32)
gender_choice=(
(1,男性),
(2,女性),
(3,其他)
)
gender=models.IntegerField(choices=gender_choice)
user_obj=models.UserInfo.objects.filter(pk=1).first()
user_obj.gender # 1
user_obj.get_gender_display() # 男性=
related_name
在通过一对多反向查询结果集给外键关联字段设置别名,就可以替代表名_set
publish=models.ForeignKey(to='Publish',on_delete=models.CASCADE,related_name='xxx')
res=models.Publish.objects.filter(pk=1).first()
# 原本是这样写
res.book_set.all()
# 用别名后
res.xxx.all()
on_delete
1、models.CASCADE
级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
2、models.SET_NULL
当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
3、models.PROTECT
当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
4、models.SET_DEFAULT
当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
5、models.SET()
当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
6、models.DO_NOTHING
什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
多对多三种创建方法详解
自动创建
authors = models.ManyToManyField(to='Author')
优点:第三张表自动创建
缺点:第三张表扩展性差
手动创建
class Book(models.Model):
pass
class Author(models.Model):
pass
class Book2Author(models.Model):
book_id = models.ForeignKey(to="Book")
author_id = models.ForeignKey(to="Author")
优点:第三张表扩展性强
缺点:无法使用正反向查询以及多对多四个方法
半自动创建
class Book(models.Model):
authors = models.ManyToManyField(to='Author',
through='Book2Author'
through_fields=('book_id','author_id')
)
class Author(models.Model):
pass
class Book2Author(models.Model):
book_id = models.ForeignKey(to="Book")
author_id = models.ForeignKey(to="Author")
优点:扩展性强并且支持正反向查询
缺点:无法使用多对多四个方法