Django框架(六)
正反向查询进阶操作
res = models. Publish. objects. filter ( book__pk= 1 ) . values( 'name' , 'book__name' )
res = models. Author. objects. filter ( book__pk= 1 ) . values( 'name' , 'book__title' )
res = models. AuthorDetail. objects. filter ( author__name= 'jason' ) . values( 'phone' , 'addr' )
res = models. Book. objects. filter ( publish__name= '南方出版社' ) . values( 'title' , 'price' )
res = models. Book. objects. filter ( authors__name= 'jason' ) . values( 'title' , 'publish_time' )
res = models. Author. objects. filter ( author_detail__phone= 110 ) . values( 'name' , 'age' )
res = models. AuthorDetail. objects. filter ( author__book__pk= 1 ) . values( 'phone' )
res = models. Author. objects. filter ( book__pk= 1 ) . values( 'author_detail__phone' )
print ( res)
ORM聚合查询
聚合函数: max 、min 、sum 、avg、count
'''聚合查询'''
from django. db. models import Max, Min, Sum, Avg, Count
没有分组之前如果单纯的时候聚合函数 需要关键字aggregate
res = models. Book. objects. aggregate( Max( 'price' ) , Min( 'price' ) , Sum( 'price' ) , Avg( 'price' ) , Count( 'pk' ) )
print ( res)
ORM分组查询
eg:models. Book. objects. annotate( )
示例:
res = models. Book. objects. annotate( author_num= Count( 'authors__id' ) ) . values( 'name' , 'author_num' )
print ( res)
res1 = models. Book. objects. annotate( author_num= Count( 'authors' ) ) . values( 'name' , 'author_num' )
print ( res1)
res = models. Publish. objects. annotate( book_price= Min( 'book__price' ) ) . values( 'name' , 'book__name' , 'book_price' )
print ( res)
res = models. Book. objects. annotate( more_author= Count( 'authors' ) ) . filter ( more_author__gt= 1 ) . values( 'name' , 'more_author' )
print ( res)
res = models. Author. objects. annotate( sum_price= Sum( 'book__price' ) ) . values( 'name' , 'sum_price' )
print ( res)
如果想按照指定的字段分组该如何处理呢?
例:models. Book. objects. values( 'price' ) . annotate( )
注:如果在分组查询报错的情况,需要修改数据库的模式。
"""
分组有一个特性 默认只能够直接获取分组的字段 其他字段需要使用方法
我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可
"""
ORM F与Q查询
F查询:能够帮助我们直接获取列表中某个字段对应的数据
F查询
示例:
1. 查询卖出数大于库存数的书籍
res = models. Book. objects. filter ( maichu__gt= ???)
from django. db. models import F
res = models. Book. objects. filter ( maichu__gt= F( 'kucun' ) )
print ( res)
2. 将所有书籍的价格提升50 块。
models. Book. objects. update( price= F( 'price' ) + 50 )
3. 将所有书的名称后面加上爆款两个字:
from django. db. models import Value
from django. db. models. functions import Concat
models. Book. objects. update( name= Concat( F( 'name' ) , Value( '爆款' ) ) )
Q查询
示例:
res = models. Book. objects. filter ( maichu__gt= 100 , price__lt= 600 )
print ( res)
from django. db. models import Q
res = models. Book. objects. filter ( Q( maichu__gt= 100 ) , Q( price__lt= 600 ) )
print ( res)
res1 = models. Book. objects. filter ( Q( maichu__gt= 100 ) | Q( price__lt= 600 ) )
print ( res1)
res2= models. Book. objects. filter ( ~ Q( maichu__gt= 100 ) | ~ Q( price__lt= 600 ) )
print ( res2)
q = Q( )
q. children. append( ( 'maichu__gt' , 100 ) )
q. children. append( ( 'price_lt' , 600 ) )
res = models. Book. objects. filter ( q)
q. connector = 'or'
print ( res)
ORM数据库查询优化
准备工作
LOGGING = {
'version' : 1 ,
'disable_existing_loggers' : False ,
'handlers' : {
'console' : {
'level' : 'DEBUG' ,
'class' : 'logging.StreamHandler' ,
} ,
} ,
'loggers' : {
'django.db.backends' : {
'handlers' : [ 'console' ] ,
'propagate' : True ,
'level' : 'DEBUG' ,
} ,
}
}
惰性查询
res = models. Book. objects. all ( )
print ( res)
获取数据表中所有数的名字:
res = models. Book. objects. values( 'name' )
print ( res)
for i in res:
print ( i. get( 'name' ) )
only方法
res = models. Book. objects. only( 'name' )
print ( res)
for i in res:
print ( i. name)
print ( i. price)
defer方法
res = models. Book. objects. defer( 'name' )
for i in res:
print ( i. price)
"""
defer与only刚好相反
defer括号内放的字段不在查询出来的对象里面 查询该字段需要重新走数据
而如果查询的是非括号内的字段 则不需要走数据库了
"""
示例:
res = models. Book. objects. all ( )
for i in res:
print ( i. publish. name)
res = models. Book. objects. select_related( )
for i in res:
print ( i. publish. name)
"""
select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据
全部封装给查询出来的对象
这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了
select_related括号内只能放外键字段 一对多 一对一
多对多也不行
"""
res = models. Book. objects. prefetch_related( 'publish' )
for i in res:
print ( i. publish. name)
"""
prefetch_related该方法内部其实就是子查询
将子查询查询出来的所有结果也给你封装到对象中
给你的感觉好像也是一次性搞定的
"""
各有优缺点:如果表特别特别大的时候使用prefetch_related品表阶段就要耗费很长的时间,而select_related子查询虽然查询两次,但是操作两个表的时间非常短效率就会胜于联表查询prefetch_related
Django事务相关操作
什么是事务?
事务:一般是指要做的或所做的事情,而且事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所做的所有更改都会被撤销。
事务的四大特性:
ACID:
原子性:
一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做
一致性:
事务必须是数据库从一个一致性状态变成另一个一致性状态。一致性 与原子性是密切相关的
隔离性:
一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据,对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰
持久性:
持久性也称永久性,指一个事务一旦提交,他对数据库中的数据的改变就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响。
MySQL中开启事务:
start transaction
事务的回滚:
rollback
事务的确认:
commit
from django. db import transaction
with transaction. atomic( ) :
sql1
sql2
在with 子代码块中书写的所有orm操作都属于同一个事务
print ( "只要不在with子代码块中就算结束事务" )
ORM常用字段及参数
AutoField( Field)
- int 自增列,必须填入参数 primary_key= True
BigAutoField( AutoField)
- bigint自增列,必须填入参数 primary_key= True
注:当model中如果没有自增列,则自动会创建一个列名为id 的列
from django. db import models
class UserInfo ( models. Model) :
username = models. CharField( max_length= 32 )
class Group ( models. Model) :
nid = models. AutoField( primary_key= True )
name = models. CharField( max_length= 32 )
SmallIntegerField( IntegerField) :
- 小整数 - 32768 ~ 32767
PositiveSmallIntegerField( PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField( Field)
- 整数列( 有符号的) - 2147483648 ~ 2147483647
PositiveIntegerField( PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField( IntegerField) :
- 长整型( 有符号的) - 9223372036854775808 ~ 9223372036854775807
BooleanField( Field)
- 布尔值类型
NullBooleanField( Field) :
- 可以为空的布尔值
CharField( Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField( Field)
- 文本类型
EmailField( CharField) :
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField( Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField( Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both' , "ipv4" , "ipv6"
unpack_ipv4, 如果指定为True ,则输入: : ffff: 192.0 .2 .1 时候,可解析为192.0 .2 .1 ,开启此功能,需要protocol= "both"
URLField( CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField( CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符( 减号)
CommaSeparatedIntegerField( CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField( Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField( Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match = None , 正则匹配
recursive= False , 递归下面的文件夹
allow_files= True , 允许文件
allow_folders= False , 允许文件夹
FileField( Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django. core. files. storage. FileSystemStorage
ImageField( FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django. core. files. storage. FileSystemStorage
width_field= None , 上传图片的高度保存的数据库字段名( 字符串)
height_field= None 上传图片的宽度保存的数据库字段名( 字符串)
DateTimeField( DateField)
- 日期+ 时间格式 YYYY- MM- DD HH: MM[ : ss[ . uuuuuu] ] [ TZ]
DateField( DateTimeCheckMixin, Field)
- 日期格式 YYYY- MM- DD
TimeField( DateTimeCheckMixin, Field)
- 时间格式 HH: MM[ : ss[ . uuuuuu] ]
DurationField( Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime. timedelta类型
FloatField( Field)
- 浮点型
DecimalField( Field)
- 10 进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField( Field)
- 二进制类型
ORM字段与MySQL字段对应关系
对应关系:
'AutoField' : 'integer AUTO_INCREMENT' ,
'BigAutoField' : 'bigint AUTO_INCREMENT' ,
'BinaryField' : 'longblob' ,
'BooleanField' : 'bool' ,
'CharField' : 'varchar(%(max_length)s)' ,
'CommaSeparatedIntegerField' : 'varchar(%(max_length)s)' ,
'DateField' : 'date' ,
'DateTimeField' : 'datetime' ,
'DecimalField' : 'numeric(%(max_digits)s, %(decimal_places)s)' ,
'DurationField' : 'bigint' ,
'FileField' : 'varchar(%(max_length)s)' ,
'FilePathField' : 'varchar(%(max_length)s)' ,
'FloatField' : 'double precision' ,
'IntegerField' : 'integer' ,
'BigIntegerField' : 'bigint' ,
'IPAddressField' : 'char(15)' ,
'GenericIPAddressField' : 'char(39)' ,
'NullBooleanField' : 'bool' ,
'OneToOneField' : 'integer' ,
'PositiveIntegerField' : 'integer UNSIGNED' ,
'PositiveSmallIntegerField' : 'smallint UNSIGNED' ,
'SlugField' : 'varchar(%(max_length)s)' ,
'SmallIntegerField' : 'smallint' ,
'TextField' : 'longtext' ,
'TimeField' : 'time' ,
'UUIDField' : 'char(32)' ,
ORM自定义字段类型
Django除了提供很多字段类型外,还支持我们自定义字段类型,所以我们在遇到某个字段没有的情况下可自定字段名与字段类型。
自定义char类型字段:
ctrl+ 鼠标左键:我们来看一下CharField内部代码是怎么写的
运行
class 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) :
'''
返回真正的数据类型及各种约束条件
:param connection:
:return:
'''
return 'char(%s)' % self. max_length
class User1 ( models. Model) :
myfiele = MyCharField( max_length= 16 , null= True )
ORM多对多创建方式
全自动
class Book ( models. Model) :
title = models. CharField( max_length= 32 )
authors = models. ManyToManyField( to= 'Authors' )
class Authors ( models. Model) :
name = models. CharField( max_length= 32 )
第三张关系表代码不需要自己写,非常的方便,还支持orm提供操作第三张关系表的方法( add, set . . . )
第三张关系表的扩展性极差( 没有办法额外添加字段)
全手动
class Book ( models. Model) :
name = models. CharField( max_length= 32 )
class Author ( models. Model) :
name = models. CharField( max_length= 32 )
class Book2Author ( models. Model) :
book_id = models. ForeignKey( to= 'Book' )
author_id = models. ForeignKey( to= 'Author' )
半自动
class Book ( models. Model) :
name = models. CharField( max_length= 32 )
authors = models. ManyToManyField( to= 'Author' ,
through= 'Book2Author' ,
through_fields= ( 'book' , 'author' )
)
class Author ( models. Model) :
name = models. CharField( max_length= 32 )
判断的本质:
通过第三张表查询对应的表,需要用到那个字段就把那个字段放前面
( '如果要通过关系表找到Book表,就把book字段放在前面' )
简化判断:
当前外键创建在那张表中,就把对应的关联字段放在前面
class Book2Author ( models. Model) :
book = models. ForeignKey( to= 'Book' )
author = models. ForeignKey( to= 'Author' )
比如:如果我们用全自动创建的多对多的关系表后,需要在关系表中添加新的字段,比如两个关系的绑定时间之类的,那么这时使用全自动就无法实现了,所以这时使用半自动就可以更方便后续的拓展
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)