day057聚合分组查询(接多表查询)

本节内容:接多表操作

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

一、聚合查询与分组查询

1、聚合

aggregate(*args, **kwargs)
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

键的名称是聚合值的标识符,值是计算出来的聚合值。

键的名称是按照字段和聚合函数的名称自动生成出来的。

如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

fe1:计算所有图书的平均价格

from django.db.models import Avg
Book.objects.all().aggregate(Avg('price'))
    # {'price__avg': 34.35}
Python

fe2:查询学生总人数

models.Student.objects.all().aggregate(c=Count('*'))
Python

1、如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。

所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
Python

2、分组查询

1、单表分组查询

#查询每一个部门名称以及对应的员工数

sql:
    select dep,Count(*) from emp group by dep;
    select dep,AVG(salary) from emp group by dep;

orm:
    queryset=models.Emp.objects.values("dep").annotate(c=Count("*"))
'''
from django.db.models import Avg,Count,Max,Min

# 查询每一个部门的人数
#  queryset=models.Emp.objects.values("dep").annotate(c=Count("*"))
#  print(queryset)  # <QuerySet [{'dep': '销售部', 'c': 1}, {'dep': '人事部', 'c': 2}]>
#
# # 查询每一个省份的平均薪水
#  queryset=models.Emp.objects.values("province").annotate(avg_salary=Avg("salary"))
#  print(queryset) # <QuerySet [{'province': '山东', 'avg_salary': 4500.0}, {'province': '河北', 'avg_salary': 5000.0}]>
Python

2、多表分组查询

annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。

总结 :跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询。 
# 1 查询每一个出版社的名字和出版过的书籍的平均价格
'''
-- sql语句:
SELECT app01_publish.name,AVG(app01_book.price) from app01_book LEFT JOIN app01_publish on
                         app01_book.publish_id = app01_publish.id
                         group by app01_publish.id,app01_publish.name
'''

# queryset=models.Publish.objects.values("id","name").annotate(avg_price=Avg("book__price"))
# queryset=models.Publish.objects.values("id","name","email","city").annotate(avg_price=Avg("book__price"))
# [{"id":1,"name":"苹果出版社","eamil":"123","city":"beijing",'avg_price': 119.0},{"id":1,"name":"橘子出版社","eamil":"123","city":"beijing",'avg_price': 155.333333.0}]

# queryset=models.Publish.objects.all().annotate(avg_price=Avg("book__price"))
# print(queryset) #<QuerySet [<Publish: 苹果出版社>, <Publish: 橘子出版社>]>
# for obj in queryset:
#     print(obj.name,obj.avg_price)

# 2 查询每一个作者的名字以及出版书籍的个数
queryset=models.Author.objects.annotate(c=Count("book")).values("name","c")
print(queryset) # <QuerySet [{'name': 'alex', 'c': 2}, {'name': 'egon', 'c': 2}]>

# 3 查询每一个书籍的名称以及作者的个数
queryset=models.Book.objects.annotate(c=Count("authors")).values("title","c")
print(queryset)

# 4 查询作者个数大于1 的每一本书籍的名称和作者个数
queryset=models.Book.objects.annotate(c=Count("authors")).filter(c__gt=1).values("title","c")
print(queryset) # <QuerySet [{'title': 'python', 'c': 2}, {'title': 'go', 'c': 2}]>

# 5 查询书籍名称包含"h"的书籍名称和作者个数
queryset=models.Book.objects.filter(title__contains="h").annotate(c=Count("authors")).values("title","c")
Python

二、F查询与Q查询

1、F查询(作用:用于比较两个字段的值)

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。

如果我们要对两个字段的值做比较,那该怎么做呢?

Django 提供 F() 来做这样的比较。
F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# F查询(仅可以对数值操作)  用于单表查询,涉及到两个变动的值进行对比,就要使用F查询
from django.db.models import F,Q,Avg
# 1、查询评论数大于100的文章
# queryset=models.Article.objects.filter(comment_num__gt=100)
# print(queryset)

# 2、查询评论数大于点赞数的文章
# queryset=models.Article.objects.filter(comment_num__gt=F("poll_num"))
#                                 # 本来要写一个固定的数字,用F以后就可以使用一个变动的值
# print(queryset)

# 3、查询点赞数大于两倍的评论数的文章
# queryset=models.Article.objects.filter(poll_num__gt=F("comment_num")*2)
# print(queryset)    # 对F得到的结果可以在进行数据运算

# 4、将所有的书籍的价格提高100元
# models.Book.objects.all().update(price=F("price")+100)
# print("???????你好")
Python

2、Q查询(filter方法中,运用与或非)

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。
如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。
& | ~  对应 与或非
# Q查询  可以通过与或非,将各种条件组合起来

# 5、查询价格大于300或者书籍名字以p开头的书籍
queryset=models.Book.objects.filter(price__lt=30)
# queryset=models.Book.objects.filter(Q(title__startswith="p") | Q(price__gt=30))
# print(queryset)


# 6、查询价格大于300或者不是2019年1月份的书籍
# q=Q(price__gt=300)|~Q(Q(pub_date__year=2019)&Q(pub_date__month=1))
# queryset=models.Book.objects.filter(q)
# print(queryset)



# F与Q联合查询,
# 点赞大于评论数的文章或者是评论数超过200文章
queryset=models.Article.objects.filter(Q(poll_num__gt=F("comment_num"))|Q(comment_num__gt=200))
print(queryset)
Python

1、查询函数可以混合使用Q 对象和关键字参数。

所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。
但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
例如:
bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                              title__icontains="python"
                             )
posted @ 2019-01-10 21:52  一片疏影  阅读(107)  评论(0编辑  收藏  举报