django orm查询语句,django orm 原生sql
一般操作细节请参考官方文档。
你必须知道13条规则。
1():查询所有结果。
2 (* * kwargs):它包含符合给定过滤标准的对象。
Get (* * kwargs):返回符合给定过滤标准的对象。只有一个返回结果,如果有多个对象或没有对象符合筛选条件,将会引发错误。
4 exclude(**kwargs):它包含不符合给定过滤标准的对象。
5 values(*field):返回一个ValueQuerySet——特殊的QuerySet。运行后,你得到的不是一系列模型的实例化对象,而是一个迭代的字典序列。
6 values_list(*field):与values()非常相似,它返回一个元组序列,values返回一个字典序列。
7 _ by (* field):对查询结果进行排序。
8 reverse():将查询结果反向排序。请注意,reverse()只能在具有已定义顺序的QuerySet上调用(在模型类的元中指定顺序或调用order_by()方法)。
9 distinct():从返回的结果中消除重复记录(如果您的查询跨越多个表,则在计算QuerySet时可能会得到重复的结果。此时可以使用distinct()。请注意,仅PostgreSQL支持按字段重复数据删除。)
0count():返回数据库中与查询匹配的对象数。
1first():返回第一条记录。
1Last():返回最后一条记录。
1exists():如果QuerySet包含数据,则返回True,否则返回False。
返回QuerySet对象的方法都是()
过滤器()
排除()
order_by()
反向()
独特()
的特殊QuerySetvalues()返回迭代字典序列。
Values_list()返回祖先的迭代序列。
返回具体对象的get()。
首先()
最后一个()
返回布尔值的方法有:exists()
返回数字的方法是count()
单表查询的神奇双下划线
models . tb1 . objects . filter(id _ _ lt=10,ID _ _ gt=1) #获取ID大于1小于10的值
models . tb1 . objects . filter(id _ _ in=[11,22,33]) #获取ID等于11,22,33的数据
模特。Tb1.objects.exclude(id__in=[11,22,33]) # not in
models . tb1 . objects . filter(name _ _ contains= ven )#获取其名称字段包含 ven 的
models . tb1 . objects . filter(name _ _ icontains= ven )# icontains不区分大小写
models . tb1 . objects . filter(id _ _ range=[1,3])# id的范围是1到3,相当于bettwen和SQL的
类似的有:startswith,istartswith,endswith,iendswith。
日期字段还可以:
模特。class . objects . filter(first _ day _ _ year=2017)
外键操作正向查找对象查找(跨表)语法:
对象。关联字段。田
示例:
book _ obj=models . book . objects . first()#第一个图书对象
Print(book_obj.publisher) #获取与这本书相关联的publisher对象
print(book _ obj . publisher . name)#获取出版社对象的名称字段查找(跨表)语法:
关联字段_ _字段
示例:
print(models . book . objects . values _ list( publisher _ _ name ))反向操作对象查找语法:
Obj。表名_集合
示例:
publisher _ obj=models . publisher . objects . first()#查找第一个发布者对象
books=publisher _ obj . book _ set . all()#查找第一家出版社出版的所有书籍
titles=books . values _ list( title )#查找第一家出版社出版的所有书籍的书名字段查找语法:
表名_ _字段
示例:
头衔=模特。publisher . objects . values _ list( book _ _ title )
Manytomanyfieldclass相关管理器“关联管理器”是在一对多或多对多关联上下文中使用的管理器。
它存在于以下两种情况:
外键多对多关系的反向查询。简单来说,当点后面可能有多个对象时,可以使用下面的方法。
方法create()
创建一个新对象,保存该对象,将其添加到关联的对象集中,并返回新创建的对象。
导入日期时间
Models.author.objects.first()。book _ set.create (title=番茄故事,publish _ date=datetime . date . today())add()
将指定的模型对象添加到关联的对象集中。
添加对象
author_objs=模型。Author.objects.filter(id__lt=3)
Models.book.objects.first()。authors.add (* author _ objs)添加id
模特。book . objects . first()authors . add(*[1,2])set()
更新模型对象的关联对象。
模型.Book.objects.first()
book_obj.authors.set([2,3])remove()
从关联对象集中移除执行的模型对象
模型.Book.objects.first()
book _ obj。作者。移除(3)清除()
从关联对象集中移除一切对象。
模型.Book.objects.first()
book_obj.authors.clear()注意:
对于外键对象,清除()和移除()方法仅在null=True时存在。
举个例子:
外键字段没设置null=True时,
课堂用书(模型。型号):
标题=模型CharField(max_length=32)
发布者=模型ForeignKey(to=Publisher)没有清除()和移除()方法:
模特Publisher.objects.first().book_set.clear()
回溯(最近一次呼叫):
模块中文件"输入"的第一行
属性错误:“相关经理”对象没有属性"清除"当外键字段设置null=True时,
课堂用书(模型。型号):
名称=型号CharField(max_length=32)
发布者=模型ForeignKey(to=Class,null=True)此时就有清除()和移除()方法:
模特Publisher.objects.first().book_set.clear()
注意:
对于所有类型的关联字段,添加()、创建()、删除()和清除(),设置()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用保存()方法。
聚合查询和分组查询聚合聚合()是查询的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
用到的内置函数:
从django.db.models导入平均值、总和、最大值、最小值、计数示例:
从django.db.models导入平均值、总和、最大值、最小值、计数
模特Book.objects.all().合计(平均值(价格))
{price__avg: 13.233333}如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
模特10 .书。对象。聚合(average _ price=Avg( price ))
{ 平均价格:13.233333}如果你希望生成不止一个聚合,你可以向聚合()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
模特Book.objects.all().汇总(平均值(价格)、最大值(价格)、最小值(价格)
{price__avg: 13.233333, price__max: Decimal(19.90 ), price__min: Decimal(9.90)}分组我们在这里先复习一下结构化查询语言语句的分组。
假设现在有一张公司职员表:
我们使用原生结构化查询语言语句,按照部分分组求平均工资:
按部门从员工组中选择部门、AVG(薪资);对象关系映射(对象关系映射)查询:
从django.db.models导入平均值
Employee.objects.values("部门")。annotate(avg=Avg(salary ).值(部门,"平均值")连表查询的分组:
结构化查询语言查询:
挑选部门名称,AVG(薪金)从员工内部联接部门on(员工。dept _ id=dept . id)group by dept _ id;对象关系映射(对象关系映射)查询:
从django.db.models导入平均值
模特部门对象。annotate(Avg=Avg(雇员_ _薪金)).值(名称,平均值)更多示例:示例1:统计每一本书的作者个数
book_list=模特.Book.objects.all().批注(author_num=Count(author ))
对于图书_列表中的对象:
.打印(对象作者编号)
.
2
一
一
示例2:统计出每个出版社买的最便宜的书的价格
publisher_list=models .出版商。对象。annotate(Min _ price=Min( book _ _ price ))
对于publisher_list中的对象:
.打印(对象最小价格)
.
9.90
19.90方法二:
模特10 .书。对象。值( publisher _ _ name ).annotate(min_price=Min(price ))
QuerySet [{publisher__name :沙河出版社, min_price: Decimal(9.90)},{publisher__name :人民出版社, min_price: Decimal(19.90)}]示例3:统计不止一个作者的图书
模特10 .书。对象。annotate(author _ num=Count( author ).过滤器(作者数量__gt=1)
QuerySet [ Book:番茄物语]示例4:根据一本图书作者数量的多少对查询集查询进行排序
模特10 .书。对象。annotate(author _ num=Count( author ).order_by(author_num )
QuerySet【书:香蕉的故事,书:橘子的故事,书:番茄的故事】例5:查询各个作者出版的书的总价。
模特。author . objects . annotate(Sum _ price=Sum( book _ _ price ))。值(名称,价格总和)
QuerySet [{name: elf , sum _ price: decimal (9.90)},{name: fairy , sum _ price: decimal (29.80)},{name: witch。
F-query和Q-query F-query在上面所有的例子中,我们构造的过滤器只是将字段值与一个常量进行比较。如果要比较两个字段的值,应该怎么做?
Django提供了f()来做这样的比较。f()的实例可以引用查询中的字段,以比较同一模型实例中两个不同字段的值。
示例1:
评论比收藏多的书
从django.db.models导入F
models . book . objects . filter(commnet _ num _ _ gt=f( keep _ num ))Django支持f()对象之间以及f()对象与常量之间的加、减、乘、除、模运算。
models . book . objects . filter(commnet _ num _ _ lt=f( keep _ num )* 2)修改操作也可以使用f函数,比如每本书提价30元。
Models.book.objects.all()。更新(价格=f(价格)30)扩展:
如果要修改char字段呢?
例如,在所有标题后添加(第一版)。
从django.db.models.functions导入Concat
从django.db.models导入值
Models.book.objects.all()。Update (title=concat (f (title )、value()、value (first edition )、value ()) Q query filter()等方法都是“与”在一起。如果需要执行更复杂的查询(比如OR语句),可以使用Q对象。
示例1:
质疑作者的名字是仙女的还是女巫的
models . book . objects . filter(Q(authors _ _ name= fairies ) Q(authors _ _ name= witches ))您可以组合and 运算符,并使用括号进行分组,以编写任何复杂的Q对象。同时,Q对象可以被~运算符求反,这允许普通查询和NOT查询的组合。
例:查询作者名字是仙女而不是2018年出版的书名。
models . book . objects . filter(q(author _ _ name=仙女)~ q (publish _ date _ _ year=2018))。值列表(标题)
QuerySet [(番茄故事,)]查询函数可以混合q对象和关键字参数。提供给查询函数的所有参数(关键字参数或Q对象)将一起进行“与”运算。但是,如果出现Q对象,它必须在所有关键参数之前。
比如查询所有出版年份为2017年或2018年,书名中有故事的书。
models . book . objects . filter(Q(publish _ date _ _ year=2018) Q(publish _ date _ _ year=2017),title _ _ I contains= story )
query set[书:番茄的故事,书:香蕉的故事,书:橘子的故事]事务
导入操作系统
if __name__==__main__ :
OS . environ . set default( DJANGO _ SETTINGS _ MODULE , BMS.settings )
进口django
django.setup()
导入日期时间
从app01导入模型
尝试:
从django.db导入事务
with transaction.atomic():
new _ publisher=models . publisher . objects . create(name= Mars Press )
models . book . objects . create(title= Orange Story ,publish _ date=datetime . date . today(),publisher _ id=10) #指定一个不存在的发布者id
例外情况为e:
打印(字符串(e))
其他鲜为人知的操作Django ORM执行原生SQL
#额外
#继续根据QuerySet执行子语句
# extra(self,select=None,where=None,params=None,tables=None,order_by=None,select_params=None)
# select和select_params是一个集合,其中和params是一个集合,tables用于设置来自哪个表。
# entry . objects . extra(select={ new _ id : select col from sometable where other col % s },select_params=(1,))
# Entry.objects.extra(其中=[headline=%s],params=[Lennon])
# Entry.objects.extra(其中=[foo=a 或bar=a , baz=a])
# entry . objects . extra(select={ new _ id : select id from TB where id % s },select_params=(1,),order_by=[-nid])
例如:
模特。UserInfo.objects.extra(
select={ newid : select count(1)from app 01 _ usertype where id % s },
select_params=[1,],
其中=[年龄%s],
params=[18,],
order_by=[-age],
tables=[app01_usertype]
)
挑选
app01_userinfo.id,
(从app01 _用户类型中选择计数(1),其中编号为1)作为新闻编号
来自应用01 _用户信息,应用01 _用户类型
在哪里
app 01 _用户信息。18岁
以.排序
app01_userinfo.age desc
# 执行原生结构化查询语言
# 更高灵活度的方式执行原生结构化查询语言语句
#从django.db导入连接,连接
# cursor=连接。cursor()# cursor=connections[ default ].光标()
#光标。执行( SELECT * from auth _ user,其中id=%s ,[1])
# row=cursor.fetchone()ORM执行原生结构化查询语言的方法
查询方法大全
##################################################################
#改变属性并返回新查询集的公共方法#
##################################################################
定义全部(自己)
# 获取所有的数据对象
定义过滤器(self,*args,**kwargs)
# 条件查询
# 条件可以是:参数,字典,问
def exclude(self,*args,**kwargs)
# 条件查询
# 条件可以是:参数,字典,问
定义选择相关的(自身,*字段)
性能相关:表之间进行加入连表操作,一次性获取关联的数据。
总结:
1.选择_相关主要针一对一和多对一关系进行优化。
2.选择_相关使用结构化查询语言的加入语句进行优化,通过减少结构化查询语言查询的次数来进行优化、提高性能。
定义预取相关(自身,*查找)
性能相关:多表连表操作时速度会慢,使用其执行多次结构化查询语言查询在计算机编程语言代码中实现连表操作。
总结:
1.对于多对多字段(ManyToManyField)和一对多字段,可以使用预取相关()来进行优化。
2.预取相关()的优化方式是分别查询每个表,然后用计算机编程语言处理他们之间的关系。
定义注释(self,*args,**kwargs)
# 用于实现聚合分组依据查询
从django.db.models导入计数、平均值、最大值、最小值和总和
v=模型UserInfo.objects.values(u_id ).批注(uid=Count(u_id ))
# SELECT u_id,COUNT(ui)AS ` uid ` FROM UserInfo GROUP BY u _ id
v=模型UserInfo.objects.values(u_id ).annotate(uid=Count(u_id ).过滤器(uid__gt=1)
# SELECT u_id,COUNT(ui _ id)AS ` uid ` FROM UserInfo GROUP BY COUNT(u _ id)为一的u _ id
v=模型UserInfo.objects.values(u_id ).annotate(uid=Count(u_id ,distinct=True)).过滤器(uid__gt=1)
# SELECT u_id,COUNT(DISTINCT ui _ id)AS ` uid ` FROM UserInfo GROUP BY COUNT(u _ id)为一的u _ id
定义不同(自身,*字段名称)
# 用于明显的去重
模特UserInfo.objects.values(nid ).独特()
#从用户信息中选择不同的突边
注:只有在一种数据库系统中才能使用明显的进行去重
def order_by(自身,*字段名称)
# 用于排序
模特UserInfo.objects.all().order_by(-id ,年龄)
def extra(self,select=None,where=None,params=None,tables=None,order_by=None,select_params=None)
# 构造额外的查询条件或者映射,如:子查询
入口。对象。extra(select={ new _ id : select col from sometable where other col % s },select_params=(1,))
Entry.objects.extra(其中=[headline=%s],params=[Lennon])
Entry.objects.extra(其中=[foo=a 或bar=a , baz=a])
入口。对象。extra(select={ new _ id : select id from TB where id % s },select_params=(1,),order_by=[-nid])
定义反转(自身):
# 倒序
模特UserInfo.objects.all().order_by(-nid ).反向()
# 注:如果存在order_by反向则是倒序,如果多个排序则一一倒序
定义延期(自身,*字段):
模特UserInfo.objects.defer(用户名, id )
或
模特UserInfo.objects.filter(.).延期(用户名, id )
#映射中排除某列数据
仅定义(自身,*字段):
#仅取某个表中的数据
模特UserInfo.objects.only(用户名, id )
或
模特UserInfo.objects.filter(.).仅(用户名, id )
定义使用(自身,别名):
指定使用的数据库,参数为别名(设置中的设置)
##################################################
#返回查询子类的公共方法#
##################################################
def raw(self,raw_query,params=None,translations=None,using=None):
# 执行原生结构化查询语言
模特userinfo。对象。raw(“从用户信息中选择*”)
# 如果结构化查询语言是其他表时,必须将名字设置为当前用户信息对象的主键列名
模特userinfo。对象。raw(选择id作为NID来源其他表)
# 为原生结构化查询语言设置参数
模特userinfo。对象。raw(从userinfo中选择id作为NID,其中NID % s ,params=[12,])
# 将获取的到列名转换为指定列名
name_map={first: first_name , last: last_name , bd: birth_date , pk: id}
人。对象。raw( SELECT * FROM some _ other _ table ,translations=name_map)
# 指定数据库
模特userinfo。对象。raw(“select * from userinfo”,using=“default”)
################### 原生SQL ############
从django.db导入连接,连接
光标=连接。cursor()# cursor=connections[ default ].光标()
光标。执行( SELECT * from auth _ user,其中id=%s ,[1])
行=游标。取一个()#取全部()/取多个(.)
定义值(自身,*字段):
# 获取每行数据为字典格式
def values_list(self,*fields,**kwargs):
# 获取每行数据为元祖
定义日期(自身,字段名称,种类,订单=ASC ):
# 根据时间进行某一部分进行去重查找并截取指定内容
#善良只能是:年份(年)、月(年-月),天(年-月-日)
#订单只能是: ASC DESC
# 并获取转换后的时间
-年份:年-01-01
-月份:年-月-01
-日:年-月-日
模特DatePlus.objects.dates(ctime , day , DESC )
def datetime(自身,字段名称,种类,顺序=ASC ,tzinfo=无):
# 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
#善良只能是"年"、"月"、"日"、"小时"、"分钟"、"秒"
#订单只能是: ASC DESC
# tzinfo时区对象
模特DDD.objects.datetimes(ctime , hour ,tzinfo=pytz .UTC)
模特DDD。对象。datetime( ctime , hour ,tzinfo=pytz.timezone(亚洲/上海))
pip3安装pytz
进口pytz
pytz.all _时区
pytz.timezone(亚洲/上海)
无定义(自身):
# 空查询对象
####################################
#执行数据库查询的方法#
####################################
极好的聚合(self,*args,**kwargs):
# 聚合函数,获取字典类型聚合结果
从django.db.models导入计数、平均值、最大值、最小值和总和
结果=模型userinfo。对象。aggregate(k=计数( u _ id ,distinct=真),n=计数( nid ))
==={k: 3, n: 4}
定义计数(自身):
# 获取个数
def get(self,*args,**kwargs):
# 获取单个对象
定义创建(自我,* *夸尔斯):
# 创建对象
def bulk_create(self,objs,batch_size=None):
# 批量插入
# batch_size表示一次插入的个数
objs=[
模特DDD(名字=r11 ),
模特106 . DDD
]
模特DDD.objects.bulk_create(objs,10)
def get_or_create(self,defaults=None,**kwargs):
# 如果存在,则获取,否则,创建
#默认值指定创建时,其他字段的值
模特.用户信息。对象。get _ or _ create(用户名= root 1 ,默认值={email: 1111111 , u_id: 2, t_id: 2})
def update_or_create(self,defaults=None,**kwargs):
# 如果存在,则更新,否则,创建
#默认值指定创建时或更新时的其他字段
模特.用户信息。对象。update _ or _ create(username= root 1 ,defaults={email: 1111111 , u_id: 2, t_id: 1})
首先定义(自己):
# 获取第一个
定义最后一个(自己):
# 获取最后一个
def in_bulk(self,id_list=None):
# 根据主键身份进行查找
id_list=[11,21,31]
模特DDD.objects.in_bulk(id_list)
定义删除(自己):
# 删除
定义更新(self,**kwargs):
# 更新
定义存在(自身):
# 是否有结果查询方法大全
姜戈终端打印结构化查询语言语句在姜戈项目的settings.py文件中,在最后复制粘贴如下代码:
日志记录={
版本:1,
disable _ existing _ loggers :False,
处理程序:{
控制台:{
级别:调试,
类":"日志记录 StreamHandler ,
},
},
"记录器":{
django.db.backends :
处理程序:[控制台],
propagate :真,
级别:调试,
},
}
}
也就是说,为您的django项目配置一个名为django.db.backends的logger实例,以查看翻译后的SQL语句。
在Python脚本中调用Django环境
导入操作系统
if __name__==__main__ :
OS . environ . set default( DJANGO _ SETTINGS _ MODULE , BMS.settings )
进口django
django.setup()
从app01导入模型
书籍=模型。Book.objects.all()
印刷品(书籍)
一般操作细节请参考官方文档。
你必须知道13条规则。
1():查询所有结果。
2 (* * kwargs):它包含符合给定过滤标准的对象。
Get (* * kwargs):返回符合给定过滤标准的对象。只有一个返回结果,如果有多个对象或没有对象符合筛选条件,将会引发错误。
4 exclude(**kwargs):它包含不符合给定过滤标准的对象。
5 values(*field):返回一个ValueQuerySet——特殊的QuerySet。运行后,你得到的不是一系列模型的实例化对象,而是一个迭代的字典序列。
6 values_list(*field):与values()非常相似,它返回一个元组序列,values返回一个字典序列。
7 _ by (* field):对查询结果进行排序。
8 reverse():将查询结果反向排序。请注意,reverse()只能在具有已定义顺序的QuerySet上调用(在模型类的元中指定顺序或调用order_by()方法)。
9 distinct():从返回的结果中消除重复记录(如果您的查询跨越多个表,则在计算QuerySet时可能会得到重复的结果。此时可以使用distinct()。请注意,仅PostgreSQL支持按字段重复数据删除。)
0count():返回数据库中与查询匹配的对象数。
1first():返回第一条记录。
1Last():返回最后一条记录。
1exists():如果QuerySet包含数据,则返回True,否则返回False。
返回QuerySet对象的方法都是()
过滤器()
排除()
order_by()
反向()
独特()
的特殊QuerySetvalues()返回迭代字典序列。
Values_list()返回祖先的迭代序列。
返回具体对象的get()。
首先()
最后一个()
返回布尔值的方法有:exists()
返回数字的方法是count()
单表查询的神奇双下划线
models . tb1 . objects . filter(id _ _ lt=10,ID _ _ gt=1) #获取ID大于1小于10的值
models . tb1 . objects . filter(id _ _ in=[11,22,33]) #获取ID等于11,22,33的数据
模特。Tb1.objects.exclude(id__in=[11,22,33]) # not in
models . tb1 . objects . filter(name _ _ contains= ven )#获取其名称字段包含 ven 的
models . tb1 . objects . filter(name _ _ icontains= ven )# icontains不区分大小写
models . tb1 . objects . filter(id _ _ range=[1,3])# id的范围是1到3,相当于bettwen和SQL的
类似的有:startswith,istartswith,endswith,iendswith。
日期字段还可以:
模特。class . objects . filter(first _ day _ _ year=2017)
外键操作正向查找对象查找(跨表)语法:
对象。关联字段。田
示例:
book _ obj=models . book . objects . first()#第一个图书对象
Print(book_obj.publisher) #获取与这本书相关联的publisher对象
print(book _ obj . publisher . name)#获取出版社对象的名称字段查找(跨表)语法:
关联字段_ _字段
示例:
print(models . book . objects . values _ list( publisher _ _ name ))反向操作对象查找语法:
Obj。表名_集合
示例:
publisher _ obj=models . publisher . objects . first()#查找第一个发布者对象
books=publisher _ obj . book _ set . all()#查找第一家出版社出版的所有书籍
titles=books . values _ list( title )#查找第一家出版社出版的所有书籍的书名字段查找语法:
表名_ _字段
示例:
头衔=模特。publisher . objects . values _ list( book _ _ title )
Manytomanyfieldclass相关管理器“关联管理器”是在一对多或多对多关联上下文中使用的管理器。
它存在于以下两种情况:
外键多对多关系的反向查询。简单来说,当点后面可能有多个对象时,可以使用下面的方法。
方法create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
导入日期时间
模特Author.objects.first().book_set.create(title=番茄物语,发布日期=日期时间。约会。今日())添加()
把指定的模型对象添加到关联对象集中。
添加对象
作者_对象=模型Author.objects.filter(id__lt=3)
模特10 .书。对象。第()位作者。添加(* author _ objs).添加编号
模特10 .书。对象。第()位作者。add(*[1,2])集合()
更新模型对象的关联对象。
模型.Book.objects.first()
book_obj.authors.set([2,3])remove()
从关联对象集中移除执行的模型对象
模型.Book.objects.first()
book _ obj。作者。移除(3)清除()
从关联对象集中移除一切对象。
模型.Book.objects.first()
book_obj.authors.clear()注意:
对于外键对象,清除()和移除()方法仅在null=True时存在。
举个例子:
外键字段没设置null=True时,
课堂用书(模型。型号):
标题=模型CharField(max_length=32)
发布者=模型ForeignKey(to=Publisher)没有清除()和移除()方法:
模特Publisher.objects.first().book_set.clear()
回溯(最近一次呼叫):
模块中文件"输入"的第一行
属性错误:“相关经理”对象没有属性"清除"当外键字段设置null=True时,
课堂用书(模型。型号):
名称=型号CharField(max_length=32)
发布者=模型ForeignKey(to=Class,null=True)此时就有清除()和移除()方法:
模特Publisher.objects.first().book_set.clear()
注意:
对于所有类型的关联字段,添加()、创建()、删除()和清除(),设置()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用保存()方法。
聚合查询和分组查询聚合聚合()是查询的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
用到的内置函数:
从django.db.models导入平均值,
Sum, Max, Min, Count示例:
from django.db.models import Avg, Sum, Max, Min, Count
models.Book.objects.all().aggregate(Avg("price"))
{price__avg: 13.233333}如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
models.Book.objects.aggregate(average_price=Avg(price))
{average_price: 13.233333}如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
{price__avg: 13.233333, price__max: Decimal(19.90), price__min: Decimal(9.90)}分组我们在这里先复习一下SQL语句的分组。
假设现在有一张公司职员表:
我们使用原生SQL语句,按照部分分组求平均工资:
select dept,AVG(salary) from employee group by dept;ORM查询:
from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")连表查询的分组:
SQL查询:
select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;ORM查询:
from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")更多示例:示例1:统计每一本书的作者个数
book_list = models.Book.objects.all().annotate(author_num=Count("author"))
for obj in book_list:
... print(obj.author_num)
...
2
1
1
示例2:统计出每个出版社买的最便宜的书的价格
publisher_list = models.Publisher.objects.annotate(min_price=Min("book__price"))
for obj in publisher_list:
... print(obj.min_price)
...
9.90
19.90方法二:
models.Book.objects.values("publisher__name").annotate(min_price=Min("price"))
QuerySet [{publisher__name: 沙河出版社, min_price: Decimal(9.90)}, {publisher__name: 人民出版社, min_price: Decimal(19.90)}] 示例3:统计不止一个作者的图书
models.Book.objects.annotate(author_num=Count("author")).filter(author_num__gt=1)
QuerySet [ Book: 番茄物语 ] 示例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序
models.Book.objects.annotate(author_num=Count("author")).order_by("author_num")
QuerySet [ Book: 香蕉物语 , Book: 橘子物语 , Book: 番茄物语 ] 示例5:查询各个作者出的书的总价格
models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price")
QuerySet [{name: 小精灵, sum_price: Decimal(9.90)}, {name: 小仙女, sum_price: Decimal(29.80)}, {name: 小魔女, sum_price: Decimal(9.90)}]
F查询和Q查询F查询在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
示例1:
查询评论数大于收藏数的书籍
from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F(keep_num))Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
models.Book.objects.filter(commnet_num__lt=F(keep_num)*2)修改操作也可以使用F函数,比如将每一本书的价格提高30元
models.Book.objects.all().update(price=F("price")+30)引申:
如果要修改char字段咋办?
如:把所有书名后面加上(第一版)
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))Q查询filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
示例1:
查询作者名是小仙女或小魔女的
models.Book.objects.filter(Q(authors__name="小仙女")Q(authors__name="小魔女"))你可以组合 和 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。
示例:查询作者名字是小仙女并且不是2018年出版的书的书名。
models.Book.objects.filter(Q(author__name="小仙女") ~Q(publish_date__year=2018)).values_list("title")
QuerySet [(番茄物语,)] 查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
例如:查询出版年份是2017或2018,书名中带物语的所有书。
models.Book.objects.filter(Q(publish_date__year=2018) Q(publish_date__year=2017), title__icontains="物语")
QuerySet [ Book: 番茄物语 , Book: 香蕉物语 , Book: 橘子物语 ] 事务
import os
if __name__ == __main__:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
import django
django.setup()
import datetime
from app01 import models
try:
from django.db import transaction
with transaction.atomic():
new_publisher = models.Publisher.objects.create(name="火星出版社")
models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id
except Exception as e:
print(str(e))
其他鲜为人知的操作Django ORM执行原生SQL
# extra
# 在QuerySet的基础上继续执行子语句
# extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# select和select_params是一组,where和params是一组,tables用来设置from哪个表
# Entry.objects.extra(select={new_id: "select col from sometable where othercol %s"}, select_params=(1,))
# Entry.objects.extra(where=[headline=%s], params=[Lennon])
# Entry.objects.extra(where=["foo=a OR bar = a", "baz = a"])
# Entry.objects.extra(select={new_id: "select id from tb where id %s"}, select_params=(1,), order_by=[-nid])
举个例子:
models.UserInfo.objects.extra(
select={newid:select count(1) from app01_usertype where id %s},
select_params=[1,],
where = [age %s],
params=[18,],
order_by=[-age],
tables=[app01_usertype]
)
"""
select
app01_userinfo.id,
(select count(1) from app01_usertype where id 1) as newid
from app01_userinfo,app01_usertype
where
app01_userinfo.age 18
order by
app01_userinfo.age desc
"""
# 执行原生SQL
# 更高灵活度的方式执行原生SQL语句
# from django.db import connection, connections
# cursor = connection.cursor() # cursor = connections[default].cursor()
# cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# row = cursor.fetchone()ORM 执行原生SQL的方法
QuerySet方法大全
##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################
def all(self)
# 获取所有的数据对象
def filter(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q
def exclude(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q
def select_related(self, *fields)
性能相关:表之间进行join连表操作,一次性获取关联的数据。
总结:
1. select_related主要针一对一和多对一关系进行优化。
2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
def prefetch_related(self, *lookups)
性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
总结:
1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化。
2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。
def annotate(self, *args, **kwargs)
# 用于实现聚合group by查询
from django.db.models import Count, Avg, Max, Min, Sum
v = models.UserInfo.objects.values(u_id).annotate(uid=Count(u_id))
# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
v = models.UserInfo.objects.values(u_id).annotate(uid=Count(u_id)).filter(uid__gt=1)
# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) 1
v = models.UserInfo.objects.values(u_id).annotate(uid=Count(u_id,distinct=True)).filter(uid__gt=1)
# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) 1
def distinct(self, *field_names)
# 用于distinct去重
models.UserInfo.objects.values(nid).distinct()
# select distinct nid from userinfo
注:只有在PostgreSQL中才能使用distinct进行去重
def order_by(self, *field_names)
# 用于排序
models.UserInfo.objects.all().order_by(-id,age)
def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# 构造额外的查询条件或者映射,如:子查询
Entry.objects.extra(select={new_id: "select col from sometable where othercol %s"}, select_params=(1,))
Entry.objects.extra(where=[headline=%s], params=[Lennon])
Entry.objects.extra(where=["foo=a OR bar = a", "baz = a"])
Entry.objects.extra(select={new_id: "select id from tb where id %s"}, select_params=(1,), order_by=[-nid])
def reverse(self):
# 倒序
models.UserInfo.objects.all().order_by(-nid).reverse()
# 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
def defer(self, *fields):
models.UserInfo.objects.defer(username,id)
或
models.UserInfo.objects.filter(...).defer(username,id)
#映射中排除某列数据
def only(self, *fields):
#仅取某个表中的数据
models.UserInfo.objects.only(username,id)
或
models.UserInfo.objects.filter(...).only(username,id)
def using(self, alias):
指定使用的数据库,参数为别名(setting中的设置)
##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################
def raw(self, raw_query, params=None, translations=None, using=None):
# 执行原生SQL
models.UserInfo.objects.raw(select * from userinfo)
# 如果SQL是其他表。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。