16.Django(基于双下划线的进阶查询、related_name、聚合查询、分组查询\F查询、Q查询、orm执行原生sql)
-
三张表的进阶查询
需求:查询指定出版社的书籍名称和作者名字
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 (了解)
面试曾经考过: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)方式1可以进行having操作1也可以进行连表操作,还可以加多个条件
res = models.Book.objects.values('publish__id').annotate(a=Avg('price')).fil ter(a__gt=100)
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)
F查询
F查询主要用于单表的查询
给book表加上两个字段,评论comment,点赞good
class Book(models.Model):
title = models.CharField(max_length=32)
publishDate = models.DateField()
comment = models.IntegerField(default=0)
good = models.IntegerField(default=0)
price = models.DecimalField(max_digits=5, decimal_places=2)
Author = models.ManyToManyField(to='Author')
# 在Terminal中输入命令
python manage.py makemigrations
python manage.py migrate
使用前需要导入模块
from django.db.models import Max, Min, Sum, Avg, Count, F, Q
-
字段之间的比较
需求:查询评论数比点赞数多的书籍
此时我们要通过F查询进行筛选
from django.db.models import Max, Min, Sum, Avg, Count, F, Q
qs = models.Book.objects.filter(comment__gt=F('good'))
print(qs) -
可以支持四则运算(+、-、*、/)
需求:评论数比点在数多50票以上的
qs = models.Book.objects.filter(comment__gt=F('good')+50)
print(qs) -
整个字段的批量操作
需求:所有书籍的价格都增加20元
models.Book.objects.all().update(price=F('price')+20) -
小结:
单表字段之间的比较以及批量操作时,用到F查询
Q查询
使用前需要导入模块
from django.db.models import Max, Min, Sum, Avg, Count, F, Q
-
可以充当
filter()查询条件中的 ’或‘ 使用,通过 | 连接需求:查询所有书籍中评论数大于200的或者点赞数大于200的书籍
qs = models.Book.objects.filter(Q(comment__gt=200) | Q(good__gt=200))
print(qs) -
Q查询还可以进行取反、与 的操作
需求:查询所有书籍中价格在100以下并且评论数在300以上的书籍。
qs = models.Book.objects.filter(~Q(price__gt=100) & Q(comment__gt=300))
print(qs)
~ :代表取反
& :代表与
# 简写:
qs = models.Book.objects.filter(prict__lt=100, comment__gt=300)
print(qs) -
支持嵌套操作
需求:查询价格大于200的,评论数或者点赞数大于100的书籍
qs = models.Book.objects.filter(Q(price__gt=200) & Q(Q(comment__gt=100) | Q(good__gt=100)))
print(obj) -
Q查询必须放在普通查询前面
需求:查询价格大于200的,评论数或者点赞数大于100的书籍
qs = models.Book.objects.filter(Q(Q(comment__gt=100)|Q(good__gt=100)),prict__gt=200)
print(qs) -
&的优先级比 |的优先级高
ORM执行原生sql语句(了解)
orm不能映射所有的sql语句,特别复杂的sql语句你用orm是写不出来的,那么我们据需要用sql语句查询数据。
我们之前使用的pymysql去执行的原生sql。但是orm给我们提供了执行原生sql语句的接口,我们可以用orm提供的执行sql语句的接口直接利用sql语句进行查询。
-
方式1:
obj = models.Book.objects.raw('select * from app01_book')
print(obj)
for ret in obj:
print(ret)
print(ret.price)
# 连表可以
obj = models.Book.objects.raw('select * from app01_book inner join app01_publish on app01_book.publish_id = app01.publish.id')
print(obj)
for ret in obj:
print(ret.name)
print(ret.title) -
方式2:(推荐的)
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1])
# 这里可以用格式化输出
ret = cursor.fetchone()
查看原生sql的第二种方式
-
第一种是配置settings
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
} -
第二种方式可以单独查询某条orm翻译的sql语句。
ret = models.Book.objects.all()
print(ret)
from django.db import connection
print(connection.queries) -

浙公网安备 33010602011771号