聚合查询、分组查询、F查询与Q查询


	1基于双下划线的跨表查询
		套路一样,用__跨表
		-一对多
		-多对多
	2 聚合查询
		-聚合函数
		    from django.db.models import Avg,Count,Max,Min,Sum
			# 计算所有图书的平均价格
			# ret=Book.objects.all().aggregate(Avg('price'))
			# print(ret)
		
	
	3分组查询
		终极总结:
			values在前,表示group by,在后,表示取值
			filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)
	4 F查询与Q查询

		-F为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了
		-Q为了构造与&,或|,非~的关系
		
	5 常用字段:必须记住,非常用字段,了解即可
	6 orm字段参数:
		-null  可以为空
		-unique  唯一性约束
		-default 默认值
		-db_index 为该字段建索引
		-只给日期类型和时间类型用
			-auto_now_add    新增数据时,默认把当前时间存入
			-auto_now        修改的时候,默认把当前时间存入
	7 关系字段
		ForeignKey
			-to  关联哪个表
			-to_field 关联的字段
			-related_name 反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。(一般不要用)
			-related_query_name :基于双下划线的反向查询之前按表名小写(一般不要用)
			-on_delete:models.CASCADE,models.SET_NULL
			-db_constraint:db_constraint=False代表,不做外键关联

二 代码示范
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "文件名字.settings")
import django

django.setup()

from app01.models import *

# 一对多新增数据
# 添加一本北京出版社出版的书
# 第一种方式
# ret=Book.objects.create(name='红楼梦',price=34.5,publish_id=1)
# print(ret.name)
# 第二种方式,存对象publish=出版社的对象,存到数据库,是一个id
# publish=Publish.objects.get(id=1)
# pk是主键,通过主键查找
# publish=Publish.objects.get(pk=1)
# publish = Publish.objects.filter(pk=2).first()
# ret = Book.objects.create(name='西游记', price=34.5, publish=publish)
# print(ret.name)
# 一对多修改数据
# book=Book.objects.get(pk=1)
# # book.publish=出版社对象
# book.publish_id=2
# book.save()
# 方式二
# book=Book.objects.filter(pk=1).update(publish=出版社对象)
# book=Book.objects.filter(pk=1).update(publish_id=1)
# 多对多新增
# 为红楼梦这本书新增一个叫lqz,egon的作者
# lqz=Author.objects.filter(name='lqz').first()
# egon=Author.objects.filter(name='egon').first()
# book=Book.objects.filter(name='红楼梦').first()
# # add 添加多个对象
# book.authors.add(lqz,egon)
# add添加作者id
# book.authors.add(1,2)
# 删除 remove,可以传对象,可以传id,可以传多个,不要混着用
# book.authors.remove(lqz)
# book.authors.remove(2)
# book.authors.remove(1,2)
# clear清空所有
# book.authors.clear()
# set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象
# book.authors.set([lqz,])
# ********这样不行,因为它打散了传过去了,相当于book.authors.set(lqz)
# book.authors.set(*[lqz,])

# lqz=Author.objects.filter(name='lqz')
# print(type(lqz))
from django.db.models.query import QuerySet

# ***************************基于对象的跨表查询
'''
一对一
正向 author---关联字段在author--->authordetail ------> 按字段
反向 authordetail------关联字段在author--->author -----> 按表名小写

'''
# 查询lqz作者的手机号 正向查询
# author=Author.objects.filter(name='lqz').first()
# # author.authordetail 就是作者详情的对象
# authordetail=author.authordetail
# print(authordetail.phone)
# 查询地址是 :山东 的作者名字 反向查询
# authordetail=AuthorDetail.objects.filter(addr='山东').first()
# # authordetail.author 这是作者对象
# author=authordetail.author
# print(author.name)

# 一对多
'''
一对多
正向 book---关联字段在book--->publish ------> 按字段
反向 publish------关联字段在book--->book -----> 按表名小写_set.all()
'''
# 正向 查询红楼梦这本书的出版社邮箱
# book=Book.objects.filter(name='红楼梦').first()
# # book.publish 就是出版社对象
# pulish=book.publish
# print(pulish.email)
# 反向 查询地址是北京 的出版社出版的图书
# publish=Publish.objects.filter(addr='北京').first()
# # publish.book_set.all() 拿出所有的图书
# books=publish.book_set.all()
# # 统计一下条数
# books=publish.book_set.all().count()
# print(books)

'''
多对多
正向 book---关联字段在book--->author ------> 按字段.all()
反向 author------关联字段在book--->book -----> 按表名小写_set.all()
'''
# 查询红楼梦这本书所有的作者
# book=Book.objects.filter(name='红楼梦').first()
# book.authors.all() #是所有的作者,是一个queryset对象,可以继续点
# print(book.authors.all())

# 查询lqz写的所有书
# lqz=Author.objects.filter(name='lqz').first()
# books=lqz.book_set.all()
# print(books)

# 连续跨表
# 查询红楼梦这本书所有的作者的手机号
# book=Book.objects.filter(name='红楼梦').first()
# authors=book.authors.all()
# for author in authors:
# authordetail=author.authordetail
# print(authordetail.phone)

# ****************************基于对象的查询---是子查询也就是多次查询
# ***************基于双下划线的查询*****
# 一对一
# 查询lqz作者的手机号 正向查询 跨表的话,按字段
# 以author表作为基表
# ret=Author.objects.filter(name='lqz').values('authordetail__phone')
# print(ret)
# 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写
# ret=AuthorDetail.objects.filter(author__name='lqz').values('phone')
# print(ret)
# 查询lqz这个作者的性别和手机号
# 正向
# ret=Author.objects.filter(name='lqz').values('sex','authordetail__phone')
# print(ret)
# 查询手机号是13888888的作者性别
# ret=Author.objects.filter(authordetail__phone='13888888').values('sex')
# print(ret)
# ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex')
# print(ret)
# ret=Book.objects.filter(price=73.8)
# print(ret.query)
# print(ret)
# F函数
from django.db.models import F

# 查询评论数大于阅读数的书
# 这样不行,进行不下去了
# ret=Book.objects.all().filter(commit_num__gt=reat_num)
# 这么来做
# ret=Book.objects.all().filter(commit_num__gt=F('reat_num'))
# print(ret)
# 把所有书的评论数加1
# 不行,进行不下去
# ret=Book.objects.all().update(commit_num+=1)
# 不行,进行不下去
# ret=Book.objects.all().update(commit_num=commit_num+1)
# 这样来做
# ret=Book.objects.all().update(commit_num=F('commit_num')+1)
# print(ret)
# 把python这本书的阅读数减5
# ret = Book.objects.all().filter(name='python').update(reat_num=F('reat_num') - 5)
# print(ret)
# Q函数 为了表示与& ,或 | ,非 ~,
from django.db.models import Q
# 查询作者名字是lqz或者名字是egon的书
# 这样行不通
# ret=Book.objects.all().filter(authors__name='lqz',authors__name='egon')
# 这样出来
# ret=Book.objects.all().filter(Q(authors__name='lqz')|Q(authors__name='egon'))
# print(ret)
# 没有意义
# ret = Book.objects.all().filter(Q(authors__name='lqz') & Q(authors__name='egon'))
# print(ret)
# 查询作者不是lqz的书
# ret=Book.objects.filter(~Q(authors__name='lqz'))
# print(ret)
# 构建很复杂的逻辑,需要用括号来区分
# ret = Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100)) | Q(pk__gt=2))
# print(ret)
三 聚合查询
from django.db.models import Avg,Count,Max,Min,Sum
# 计算所有图书的平均价格
# ret=Book.objects.all().aggregate(Avg('price'))
# print(ret)
# 计算图书的最高价格
# ret=Book.objects.all().aggregate(Max('price'))
# print(ret)
#他是queryset的终止子句
# 计算图书的最高价格,最低价格,平均价格,总价
#
# ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))
# print(ret)

#分组查询annotate()
# 统计每一本书作者个数
# ret=Book.objects.all().annotate(c=Count('authors'))
# print(ret)
# for r in ret:
# print(r.name,'---->',r.c)

# ret=Book.objects.all().annotate(c=Count('authors')).values('name','c')
# print(ret)
# 统计每一个出版社的最便宜的书(以谁group by 就以谁为基表)
# ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m')
# print(ret)
# 统计每一本以py开头的书籍的作者个数
# ret1=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
# print(ret1)
# 总结: group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值
# 总结终极版本
# values在前,表示group by 在后,表示取值
# filter在前,表示where条件,在后表示having
# 统计每一本以py开头的书籍的作者个数--套用模板
# ret2=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c')
# print(ret2)
# 查询各个作者出的书的总价格
# ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s')
# ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s')
# print(ret)
#查询名字叫lqz作者书的总价格
# ret=Author.objects.all().values('pk').filter(name='lqz').annotate(s=Sum('book__price')).values('name','s')
# print(ret)
# 查询所有作者写的书的总价格大于30
# ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s')
# ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s')
# print(ret)
# 总结终极版本
# values在前,表示group by 在后,表示取值
# filter在前,表示where条件,在后表示having
# 统计不止一个作者的图书

ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c')
# ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num')
print(ret)
 
posted @ 2018-11-14 18:17  不沉之月  阅读(223)  评论(0编辑  收藏  举报