MON.神奇的双下划线及多表操作

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、年龄在 1835 岁之间
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)  # 书籍 id 为 1 的书籍绑定一个主键为 1 的作者
book_obj.authors.add(12)  # 支持传入多个

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)  # Publish.object 得到出版社对象


2、查询书籍主键为 1 的作者
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.authors  # table.Author.None
res = book_obj.authors.all()  # <Queryset> [<Author: Author object>]


3、查询作者 Gnasche 的电话号码
author_obj = models.Author.objects.filter(name='Gnasche').first()
res = author_obj.author_detail  # AuthorDetail objects

'''
注意
		在书写 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')  # <Queryset [{'author_detail'}]>
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 中的 group_by
'''
MySQL 中分组查询的特点
		分组之后默认只能获取到分组的依据
		组内其他字段都无法直接获取
				严格模式 -- ONLY_FULL_GROUP_BY
'''

1、统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors')).values('title', 'author__name')  # models 后面跟什么,就按什么分组,authors 相当于 authors__id
"""
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()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值