Django基础入门⑫:Django 对象查询详解,分组聚合

🏘️🏘️个人简介:以山河作礼
🎖️🎖️:Python领域新星创作者,CSDN实力新星认证,阿里云社区专家博主,CSDN内容合伙人
🎁🎁:Web全栈开发专栏:《Web全栈开发》免费专栏,欢迎阅读!
🎁🎁:文章末尾扫描二维码可以加入粉丝交流群,不定期免费送书。


Django 对象查询详解

F对象查询与Q对象查询,它们是 Django 提供的查询方法,而且非常的简单的高效,对于一些特殊的场景需求应用起来非常的合适,在本节我们将对这两种查询方法进行讲解,帮助大家掌握它们的使用方法以及适合应用的场景。

F对象查询

F对象主要用于模型类的 A 字段属性与 B 字段属性两者的比较,即操作数据库中某一列的值。通常是对数据库中的字段值在不获取的情况下进行操作。
F 对象内置在数据包django.db.models中,所以使用时需要提前导入。
如下所示:

from django.db.models import F

它的语法格式如下所示:

from django.db.models import F
F('字段名')
  • 在使用F对象进行查询的时候需要注意:一个 F() 对象代表了一个 Model 的字段的值;F对象可以在没有实际访问数据库获取数据值的情况下对字段的值进行引用。
  • Django 支持对 F对象引用字段的算术运算操作,并且运算符两边可以是具体的数值或者是另一个 F 对象,下面我们通过实例进一步认识 F对象。
from django.db.models import F
from index.models import Book

#给Book所有实例价格(retail_price)涨价20元 
Book.objects.all().update(retail_price=F('retail_price')+20) #获取该列所有值并加20

#利用传统的方法实现涨价20元
books = Book.objects.all()
    for book in books:
        book.retail_price += 20
        book.save()
    return HttpResponse("增加价格成功")

通过上述实例可以看出,使用 F 对象相对传统的方法要简单的多。那么如何通过 F 对象实现两个字段值(列)之间的比较呢?实例如下所示:

#对数据库中两个字段的值进行比较,列出哪儿些书的零售价高于定价 
books = Book.objects.filter(retail_price__gt=F('price')) 
for book in books: 
    print(book.title, '定价:', book.price, '现价:', book.retail_price)

Q对象查询

Q 对象相比 F 对象更加复杂一点,它主要应用于包含逻辑运算的复杂查询。Q 对象把关键字参数封装在一起,并传递给 filter、exclude、get 等查询的方法。多个 Q 对象之间可以使用&或者|运算符组合(符号分别表示与和或的关系),从而产生一个新的 Q 对象。当然也可以使用~(非)运算符来取反,从而实现NOT查询。
Q 对象的导入方式如下所示:

from django.db.models import Q

它和 Q 对象位于一个数据包里面。常用语法格式如下:

from django.db.models import Q
Q(条件1)|Q(条件2)  # 条件1成立或条件2成立
Q(条件1)&Q(条件2)  # 条件1和条件2同时成立
Q(条件1)&~Q(条件2)  # 条件1成立且条件2不成立
#...等

最简单的 Q 对象的使用方法是将单个字段类属性作为参数进行查询,实例如下:

#查询 书籍的title中包含有字母P的
from index.models import Book
from django.db.models import Q
Book.objects.filter(Q(title__contains="P"))

# <QuerySet [<Book: Book object (1)>]>

但时 Q 对象在实际的应用中往往是和逻辑运算符一起使用,如下所示:

#多个Q对象组合
from index.models import Book
from django.db.models import Q 
#查找c语言中文网出版的书或价格低于35的书 
Book.objects.filter(Q(retail_price__lt=35)|Q(pub_id='2'))#两个Q对象是或者的逻辑关系
#查找不是c语言中文出版的书且价格低于45的书 
Book.objects.filter(Q(retail_price__lt=45)&~Q(pub_id='2'))#条件1成立条件2不成立

Django分组聚合

聚合查询是指对一个数据表(Model)中某个字段的数据进行部分或者全部统计查询的一种方式,比如所有全部书的平均价格或者是书籍的总数量等等,在这些时候就会使用到聚合查询这种方法。

聚合查询

  • 对数据表计算统计值,需要使用 aggregate 方法,提供的参数可以是一个或者多个聚合函数,aggregate 是 QuerySet的一个子句,它的返回值是一个字典类型,键是聚合的关键字,值是聚合后的统计结果。
  • 不带分组的聚合查询是指对将全部数据进行集中统计查询,Django定义了一些常用的聚合函数,比如求平均值(Avg)、计数(Count)、求最值(Max和Min)以 Sum 求和。它们统一定义在django.db.models模块中,所以再使用聚合函数时,同样需要提前导入,为了方便使用,我们采用下面的方式引入:
from django.db.models import *

它的语法格式如下所示,它的返回值是一个字典,以统计结果变量名为 key,以统计值为 value:

MyModel.objects.aggregate(统计结果变量名=聚合函数('列名'))

我们通过求所有书籍的价格平均值与所书籍数量来进行实例演练:

#求所有书籍的平均价格
from index.models import Book
from django.db.models import *

result =Book.objects.aggregate(myAvg=Avg('price'))
print("平均价格是:", result['myAvg'])
print("result=", result)
#result= {'myAvg': Decimal('47.800000')}

#求一共有多少本书
result =Book.objects.aggregate(MyCulate=Count('title'))
print("数据记录总个数是:", result['MyCulate'])
print("result=", result)
#result= {'MyCulate': 5}

#传递多个聚合函数一起求值
result=Book.objects.aggregate(l=Min("price"),m=Max("price"),n=Avg("retail_price"))
print("result=",result)
#result= {'l': Decimal('25.00'), 'm': Decimal('65.00'), 'n': Decimal('127.800000')}

分组聚合应用

分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。简单的理解就是对 QuerySet中的每一个 Model 对象都生成一个统计值。分组聚合使用 annotate 方法完成。
它的语法格式和聚合查询一样如下所示:

QuerySet.annotate(结果变量名=聚合函数('列名'))

分组聚合的实现主要两个步骤:

  • 首先使用 MyModel.objects.values 获得要分组聚合的列,它的返回结果是一个 QuerySet 类型的字典,
  • 然后通过 QuerySet.annotate(变量名=聚合函数(‘列名’)) 的方法分组聚合得到相应的结果。

下面我们通过实例进行说明,通过分组聚合查询获取价格相同的书籍数量:

#在index/views.py 添加代码
from django.db.models import Count
from index.models import Book,PubName
def test_annotate(request):
    # 得到所有出版社的查询集合QuerySet
    bk_set = Book.objects.values('price')
    # bk=Book.objects.get(id=1)
    # print('书名:',bk.title,'出版社是:',bk.pub.pubname)
    # 根据出版社QuerySet查询分组,出版社和Count的分组聚合查询集合
    bk_count_set = bk_set.annotate(myCount=Count('price'))  # 返回查询集合
    for item in bk_count_set: #通过外键关联进行查询bk_set.pub.pubname
        print("价格是:", item['price'], "同等价格书籍数量:", item['myCount'])
    return HttpResponse('请在CMD命令行控制台查看结果')
#路由配置为:path('annotate/',views.test_annotate)

会得到如下输出:

价格是: 59.00 同等价格书籍数量: 1
价格是: 25.00 同等价格书籍数量: 1
价格是: 45.00 同等价格书籍数量: 2
价格是: 65.00 同等价格书籍数量: 1

总结

本节主要讲解了聚合查询以及分组聚合查询的使用方法,还给大家介绍了几个常用的聚合函数。聚合查询和分组查询分别调用不同的方法来实现,聚合查询是 aggregate,而分组聚合查询是 annotate。后者经常配合 values 方法来选取要分组的字段。

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

以山河作礼。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值