三张表的进阶查询
需求:查询指定出版社的书籍名称和作者名字
Publish、Book、Author涉及三张表,我们就有三种方式。涉及多少张表,我们就有多少种方式去做。
正向查询
obj = models.Book.objects.filter(Publish__name=‘xx出版社‘).values(
‘title‘,
‘Author__name‘,
)
反向查询
# 方式1:
obj = models.Publish.object.filter(name=‘xx出版社‘).values(
‘book__title‘,
‘book__author__name‘,
)
?
?
# 方式2:
obj = models.Author.objects.filter(book__Publish__name=‘IT出社‘).values(
‘book__title‘,
‘name‘,
)
print(obj)
四张表的进阶查询
需求:手机号为166开头的作者出版的所有书籍名称以及出版社名称
AuthorDetail、Author、Book、Publish
正向查询
# 方式1:
obj = models.Author.objects.filter(AuthorDetail__telephone__startswith=‘166‘).values(
‘book__title‘,
‘book__Publish__name‘
)
?
?
?
# 方式2:
obj = models.Book.objects.filter(Author__AuthorDetail__telephone__startswith=‘166‘).values(
‘title‘,
‘Publish__name‘,
)
print(obj)
反向查询
# 方式1:
obj = models.AuthorDetail.objects.filter(telephone__startswith=‘166‘).values(
‘author__book__title‘,
‘author__book__Publish__name‘,
)
print(obj)
?
?
# 方式2:
obj = models.Publish.objects.filter(book__Author__AuthorDetail__telephone__startswith=‘166‘).values(
‘book__title‘,
‘name‘,
)
print(obj)
面试曾经考过:related_name是什么?用在哪里?
基于对象的查询如果我们进行反向查询需要获取关联表的表名;基于双下划线的连表查询我们在连表的时候,也需要获取表的名字__。
‘‘‘
测试:
我们给book表中的publish字段加一个此属性
‘‘‘
Publish = models.ForeignKey(to=‘Publish‘, on_delete=models.CASCADE, related_name=‘xx‘)
?
# 重新makemirations、migrate
?
?
?
?
# 测试基于对象的查询
?
# 正向查询:需求:查询指定书的出版社
obj = models.Book.objects.get(title=‘指定的书名‘)
print(obj.publish.name) # related_name 不影响
?
# 反向查询:需求:查询指定出版社出版的书名
obj = models.Publish.objects.get(name=‘指定出版社‘)
# print(obj.book_set.all()) # 查不到
print(obk.xx.all())
?
related_name 这个属性替代了反向查询时需要 类名_set 这个方法
?
?
?
?
# 基于双下划线连表的操作
?
# 正向查询:需求:查询指定书的出版社
obj = models.Book.objects.filter(title=‘指定书‘).values(
‘publish_name‘,
)
print(obj)
?
# 反向查询:需求:查询指定书的出版社
# obj = models.Publish.objects.filter(book__title=‘指定书名‘).values(
# ‘publihs__name‘,
# )
# print(obj) # 报错
?
obj = models.Publish.objects.filter(xx__title=‘指定书名‘).values(
‘publish__name‘,
)
print(obj)
related_name只是适用于反向查询
基于对象那个的反向查询时需要类名_set
这种方法替换成了你设置的related_name就行了;基于双下划线的反向查询将类名__字段
替换成related_name__字段
。
mysql中有什么聚合函数?
统计:count()
最大:max()
最小:min()
求和:sum()
平均值:avg()
?
聚合字段:concat()
orm也是支持这些聚合函数的
需要先引入
from django.db.models import Max,Min,Avg,Sum,Count
使用聚合查询需要使用aggregate()
,在括号里面写聚合函数
# 注意:聚合函数导入和使用时,开头字母要大写
?
from django.db.models import Max,Min,Avg,Sum,Count
num = models.Book.objects.aggregate(Sum(‘price‘))
print(num)
aggregate()
这个方法返回的是一个字段,返回一个字段就意味着这句话终结了。结束了。
将同类的分成一组统计或者计算一些内容,一般都是找重复性较高的字段进行分组。在orm中有两种方式(一般多用于第二种)
方式1:
需求:查询每个出版社的书籍的平均价格
# 原生mysql语句
select avg(price) from app01_book group by publish_id;
# orm 语句
res = models.Book.objects.values(‘Publish_id‘).annotate(a=Avg(‘price‘))
# 这里的values加分组的字段也就是原生mysql语句中的group by。
# annotate里面放置的就是分组之后要统计的内容。
print(res)
方式1的优点:可以进行多条件的分组
res = models.Book.objects.values(‘publish_id‘,‘id‘).annotate(a=Avg(‘price‘)) print(res)
方式2:
需求:拆线呢每个出版社出版的书籍的平均价格
原理是基于双下划线连表操作的
res = models.Publish.objects.annotate(a=Avg(‘book__price‘))
print(res)
res = models.Publish.objects.annotate(a=Avg(‘book__price‘)).values(‘name‘,‘a‘)
print(res)
优点:在此种写法基础上,可以进行进一步的筛选
需求:查询每个出版社出版的书籍的平均价格大于100的
res = models.Publish.objects.annotate(a=Avg(‘book_price‘)).valeus(‘name‘,‘a‘).filter(a__gt=100)
# filter 充当的是having的作用
print(res)
16.Django(基于双下划线的进阶查询、related_name、聚合查询、分组查询)
原文:https://www.cnblogs.com/muyangxiaodong/p/13067773.html