MON.神奇的双下划线及多表操作
神奇的双下滑线查询
1 、年龄大于 35 岁的数据
res = models. User. objects. filter ( age__gt= 35 )
2 、年龄小于 35 岁的数据
res = models. User. objects. filter ( age__lt= 35 )
3 、大于等于
res = models. User. objects. filter ( age__gte= 35 )
4 、小于等于
res = models. User. objects. filter ( age__lte= 35 )
5 、年龄是 18 或者 35 或者 40
res = models. User. objects. filter ( age__in= [ 18 , 35 , 40 ] )
6 、年龄在 18 ,35 岁之间
res = models. User. objects. filter ( age__rang= [ 18 , 35 ] )
7 、模糊查询 - - 查询出名字中含有 n 的数据
res = models. User. objects. filter ( name__contains= 's' )
res = models. User. objects. filter ( name__icontains= 's' )
8 、以 'j' 开头、结尾
res = models. User. objects. filter ( name__startswith= 's' )
res = models. User. objects. filter ( name__endswith= 's' )
9 、查询指定时间
res = models. User. objects. filter ( register_time__month= '1' )
res = models. User. objects. filter ( register_time__year= '1' )
多表操作
一对多外键增删改查
1 、增
No. 1 Scheme - - 直接写实际字段 id
models. Book. object . create( title= '三国演义' , price= 123 , publish_id = 1 )
No. 2 Scheme - - 虚拟字段 对象
publish_obj = models. Book. object . filter ( pk= 2 ) . first( )
models. Book. object . create( title= '三国演义' , price= 123 , publish_id= publish_obj)
2 、删
models. Publish. objects. filter ( pk= 1 ) . delete( )
3 、改
No. 1 Scheme
models. Book. objects. filter ( pk= 1 ) . update( publish= 2 )
publish_obj = models. Book. objects. filter ( pk= 1 ) . first( )
models. Book. objects. filter ( pk= 1 ) . update( publish= publish_obj)
一对多关系外键值在进行增改操作时,既可以使用实际 id 值,也可以使用对象,是取决于使用实际字段还是虚拟字段
多对多外键增删改查
1 、增 - - 绑定作者
No. 1 Scheme - - 直接传入实际 id 字段
book_obj = models. Book. objcts. filter ( pk= 1 ) . first( )
print ( book_obj. authors)
book_obj. authors. add( 1 )
book_obj. authors. add( 1 ,2 )
No. 2 Scheme - - 虚拟字段 对象
author_obj1 = models. Book. objcts. filter ( pk= 1 ) . first( )
author_obj2 = models. Book. objcts. filter ( pk= 2 ) . first( )
author_obj3 = models. Book. objcts. filter ( pk= 3 ) . first( )
book_obj. authors. add( author_obj1)
book_obj. authors. add( author_obj2, author_obj3)
"""
add 给第三张表添加数据
括号内可以传实际 id 字段也可以传对象,并且支持多个
"""
2 、删 - - 解除绑定
No. 1 Scheme - - 直接传入实际 id 字段
book_obj. authors. remove( 1 )
book_obj. authors. remove( 2 , 3 )
No. 2 Scheme - - 虚拟字段 对象
author_obj1 = models. Author. objects. filter ( pk= 1 ) . first( )
author_obj2 = models. Author. objects. filter ( pk= 2 ) . first( )
book_obj. authors. remove( author_obj1, author_obj2)
"""
remove
括号内可以传实际 id 字段也可以传对象,并且支持多个
"""
3 、改
No. 1 Scheme - - 直接传入实际 id 字段
book_obj = models. Book. objcts. filter ( pk= 1 ) . first( )
book_obj. authors. set ( [ 1 , 2 ] )
book_obj. authors. set ( [ 3 ] )
No. 2 Scheme - - 虚拟字段 对象
author_obj1 = models. Author. objects. filter ( pk= 1 ) . first( )
author_obj2 = models. Author. objects. filter ( pk= 2 ) . first( )
boook_obj. authors. set ( [ author_obj1, author_obj2] )
"""
set
括号内必须是一个可迭代对象,该对象可以是实际 id 字段也可以是对象,并且支持多个
先删除后新增
"""
4 、清空
book_obj = models. Book. objcts. filter ( pk= 1 ) . first( )
book_obj. authors. clear( )
正反向的概念
正向 - 反向
看外键关系在哪张表中,由该表查询其他表中与其关联的数据即为正向;反之则为反向
一对一和多对多蒸饭箱的判断也是如此
'''
正向查询按 -- 字段
反向查询按 -- 表名小写
_set
...
'''
多表查询
子查询 – 基于对象的跨表查询
正向查询
1 、查询数据主键为 1 的出版社
book_obj = models. Book. objects. filter ( pk= 1 ) . first( )
res = book_obj. publish
print ( res)
2 、查询书籍主键为 1 的作者
book_obj = models. Book. objects. filter ( pk= 1 ) . first( )
res = book_obj. authors
res = book_obj. authors. all ( )
3 、查询作者 Gnasche 的电话号码
author_obj = models. Author. objects. filter ( name= 'Gnasche' ) . first( )
res = author_obj. author_detail
'''
注意
在书写 ORM 语句的时候跟书写 SQL 语句是一样的
不要企图依次性将 ORM 语句写完,如果比较复杂,最好分段书写
正向结果什么时候需要加 .all()
当结果可能有多个值得时候就需要加 .all()
如果结果有且仅有一个则直接拿到数据对象
'''
反向查询
1 、查询出版社是东方出版社的书籍
publish_obj = models. Publish. objects. filter ( name= '东方出版社' ) . first( )
res = publish_obj. book_set. all ( )
2 、查询作者 Gnasche 写过的书
author_obj = models. Author. objects. filter ( name= 'Gnasche' )
res = author_obj. book_set. all ( )
3 、查询手机号是 110 的作者姓名
author_detail_obj = models. Author_detail. objects. filter ( phone= 110 ) . first( )
res = author_detail_obj. author
'''
注意
基于对象反向查询时
当查询结果可以有多个时,就必须加 _set.all()
当查询结果有且仅有一个的时候,不需要加 _set.all()
'''
联表查询 – 基于双下划线的跨表查询
1 、查询 Gnasche 的手机号码
No. 1 Scheme - - 正向
res = models. Author. objects. filter ( name= 'Gnasche' ) . values( 'author_detail__phone' )
res = models. Author. objects. filter ( name= 'Gnasche' ) . values( 'author_detail__phone' , 'name' )
No. 2 Scheme - - 反向
res = model. AuthorDetail. object . filter ( author__name= 'Gnasche' ) . values( 'phone' , 'author__name' )
2 、查询数据主键为 1 的出版社名称和书籍名称
No. 1 Scheme - - 正向
res = models. Book. objects. filter ( pk= 1 ) . values( 'title' , 'publish__name' )
No. 2 Scheme - - 反向
res = moels. Publish. filter ( book__id= 1 ) . values( 'name' , 'book__title' )
3 、查询书籍主键为 1 的作者的姓名
No. 1 Scheme - - 正向
res = models. Book. objects. filter ( pk= 1 ) . values( 'author__name' )
No. 2 Scheme - - 反向
res = models. Author. filter ( 'book__id' = 1 ) . values( 'name' )
4 、查询书籍主键是 1 的作者的手机号
No. 1 Scheme
res = models. Book. objects. filter ( pk= 1 ) . values( 'authors__name_detail__phone' )
'''
只要掌握了正反向的概念以及双下划线
那么就可以无限制的跨表
'''
聚合查询
只要是与数据库相关的模块
基本上都在 django.db.models 中 如果不存在上述模块中,则应在 django.db 中 聚合查询通常情况都是配合分组一起使用
from django. db. models import Max, Min, Sum, Count, Avg
1 、所有书的平均价格
res = models. Book. objects. aggregate( Avg( 'price' ) )
2 、综合应用
res = models. Book. objects. aggregate( Max( 'price' ) , Min( 'price' ) , Sum( 'price' ) , Count( 'pk' ) , Avg( 'price' ) )
分组查询 – annotate
'''
MySQL 中分组查询的特点
分组之后默认只能获取到分组的依据
组内其他字段都无法直接获取
严格模式 -- ONLY_FULL_GROUP_BY
'''
1 、统计每一本书的作者个数
res = models. Book. objects. annotate( author_num= Count( 'authors' ) ) . values( 'title' , 'author__name' )
"""
author_num 是我们自己定义的字段,用来存储统计出来的每本书对应的作者个数
"""
2 、统计每个出版社卖的最便宜的书的价格
res = models. Publish. objects. annotate( cheapest_price= Min( 'book__price' ) ) . values( 'name' , 'cheapest_price' )
3 、统计不止一个作者的图书
res = models. Book. objects. annotate( author_num= Count( 'authors' ) ) . fiter( author_num__gt== 1 ) . values( 'title' , 'author_num' )
'''
只要 ORM 语句得出的结果还是一个 Queryset 对象
那么他就可以继续无限地使用 Queryset 对象封装方法
'''
4 、查询每个作者出的书的总价格
res = models. Author. objects. annotate( total_price= Sum( 'book_price' ) ) . values( 'name' , 'total_price' )
'''
如果分组报错,需要修改 MySQL 中的严格模式
'''
按照指定字段分组
按照价格分组
models. Book. objects. values( 'price' ) . annotate( )