一篇文章带你了解Django ORM操作(高端篇)

开发 前端
本篇主要补充的是一些高端操作,例如聚合操作,分组操作,分组再筛选操作,F查询和Q查询。

[[373732]]

前言

上次两篇基本学完的Django ORM各种操作,怎么查,各种查。感兴趣的小伙伴可以戳这两篇文章学习下,一篇文章带你了解Django ORM操作(进阶篇)、一篇文章带你了解Django ORM操作(基础篇)。

但是还是遗留了一些技能。,再来瞅瞅吧!

查询

聚合操作

聚合操作,不要被名字吓到了,通常用在筛选完一些数据之后,求一下平均值了,什么的。

例如:求所有书的总价格和平均价格

原生sql

  1. SELECT 
  2.     SUM(price) AS "所有书总价格"
  3.     avg(price) AS "所有书平均价格" 
  4. FROM 
  5. web_book; 

T SUM(price) AS "所有书总价格", avg(price) AS "所有书平均价格"FROMweb_book;

执行结果


ORM

  1. price = models.Book.objects.all().aggregate(Sum("price"),Avg("price"), ) 
  2. print(price) 

执行结果


可以发现和上面是一样的,但是会发现列名是默认是字段__聚合函数名。

原生sql是可以指定显示的列名的,同样,ORM也可以。

代码

  1. # 需要导入的包 
  2. from django.db.models import Avg,Sum 
  3.  
  4. price = models.Book.objects.all().aggregate(所有书总价格=Sum("price"), 所有书平均价格=Avg("price"), ) 
  5. print(price) 

执行结果


:price的类型直接就是dict,所以,在这是不能查看原生sql的。

但是上述ORM对应的原生SQL确实如上,所以那样理解就行了。

分组操作

分组操作,就是将某一列,相同的值进行压缩,然后就可以得出压缩值的数量。

如果压缩的是外键,还可以取出外键的详细信息。

示例:查询出每个出版社出版的数量。

通过研究表结构发现,每出版的书,都在book表中记录,并且每本书会外键一个出版社id。


如果我们能对出版社id进行压缩,然后再求出压缩出版社id里面对应的数量。

啧啧,这不就出来了吗?

代码

  1. from django.db.models import Count 
  2.  
  3. ret = models.Book.objects.values("publish_id").annotate(publish_count=Count("publish_id")) 
  4. print(ret) 

执行结果


原生sql

  1. SELECT 
  2.     `web_book`.`publish_id`, 
  3.     COUNT(`web_book`.`publish_id`) AS `publish_count` 
  4. FROM 
  5.     `web_book` 
  6. GROUP BY 
  7.     `web_book`.`publish_id`; 

ORM分组和原生SQL对应图

这一块,我记得当初我迷茫了一段时间,主要是不知道如何和原生SQL对应上,根据多次测试经验,对应图如下。


分组获取外键字段信息

上述确实可以通过分组实现了功能。

但是上述只能获取出版社id,并不能获取出版社名啥的,但是如何获取压缩外键字段详细信息呢?

代码

  1. ret = models.Book.objects.values("publish_id").annotate(publish_count=Count("publish_id")).values("publish__title","publish__phone","publish_count"
  2. print(ret) 

执行结果


:分组(annotate)后面跟的values。

里面只能写外键字段的列和annotate里面的列,不能写其他。

如果分组分的不是外键字段,那就不能再跟values!

分组再筛选

分组再筛选本质就是原生sql的group by .. having,将压缩完的数据在进行条件判断。

但是对压缩的数据进行判断只能通过having。

示例:查询出版社出版的书大于2本的数据。

代码

  1. ret = models.Book.objects.values("publish_id") \ 
  2.     .annotate(publish_count=Count("publish_id")) \ 
  3.     .filter(publish_count__gt=2) 
  4. print(ret) 

执行结果


F查询

有时候,我们可能有这样的需求,就是两个列之间进行比较。

比如经典问题,一个商品,找到收藏数大于销量的商品等之类的两列进行比较的需求。

示例:查询book表,评论数小于收藏数的数据。

代码

  1. from django.db.models import F 
  2.  
  3. book = models.Book.objects.filter(comment_num__lt=F("collect_num")) 
  4. print(book) 

实际结果


执行结果


F对象还支持加减乘除后的比较

示例:评论数小于两倍收藏数的数据。

代码

可是*,也可以是-,+,÷

  1. from django.db.models import F 
  2.  
  3. book = models.Book.objects.filter(comment_num__lt=F("collect_num")*2) 
  4. print(book) 

执行结果


F对象还适用于更新

代码

  1. models.Book.objects.all().update(price=F("price")+30) 

Q查询

通常情况下,我们使用的filter(条件1,条件2,...),执行的都是and查询。

但是通常一些时候,我们需要执行or查询。

比如book表,查询title=<<大明帝国>> or title=<<安史之乱>>的。

这时候,如果使用Django ORM,就只能使用Q查询构建条件。

代码

  1. from django.db.models import Q 
  2.  
  3. books = models.Book.objects.filter(Q(title="<<大明帝国>>") | Q(title="<<安史之乱>>")) 
  4. print(books) 

执行结果


:|是or的意思,&是and的意思。

所以,如果将上述的|换成&,filter(条件1,条件2,...)一个意思,还是and。

Q查询之~

~相当于not。

示例:查询title = "<<大明帝国>>" or title != "<<安史之乱>>"。

代码

  1. from django.db.models import Q 
  2.  
  3. books = models.Book.objects.filter(Q(title="<<大明帝国>>") | ~Q(title="<<安史之乱>>")) 
  4. print(books) 

执行结果


Q查询和and混合查询

Q查询和and查询同时出现,Q查询必须在其他查询之前。

示例:查询title = "<<大明帝国>>" or title != "<<安史之乱>>" 并且publish_id=1的。

代码

  1. from django.db.models import Q 
  2.  
  3. books = models.Book.objects.filter(Q(title="<<大明帝国>>") | ~Q(title="<<安史之乱>>"),publish_id=1) 
  4. print(books) 

执行结果


动态构造Q查询

一些时候,我们可能并不太确定有什么条件。

可能是动态传的,传过来多少,就拼接多少。

Q查询,就能做到这个,在做动态Q查询时,动态Q不仅支持or,还支持and。

示例:查询publish_id=1或者title模糊=大明 的书。

代码

  1. q = Q() 
  2. # 查询方式,or还是and 
  3. q.connector = "or"  # or,and 
  4. # publish_id=1 
  5. q.children.append(("publish_id""1")) 
  6. # title__contains="大明" 
  7. q.children.append(("title__contains""大明")) 
  8.  
  9. books = models.Book.objects.filter(q) 
  10. print(books) 

执行结果


上面说了那么多,终于算是大概说完了,来简单看一下怎么添加一条数据吧。

示例:添加一本书

代码

方式一,通过objects.create。

这种方式用的最多。

  1. models.Book.objects.create
  2.     title="<<人类简史2>>"
  3.     price=66.66, 
  4.     PublishDate="2020-01-02"
  5.     comment_num=23, 
  6.     collect_num=12, 
  7.     # 外键字段 django models对应的mysql 为 字段_id 
  8.     publish_id=1, 
  9.     # publish字段需要是一个 Publish 对象 
  10.     # publish=models.Publish.objects.filter(id=1) 

方式二,通过model对象.save()。

  1. book_obj = models.Book( 
  2.     title="<<人类简史2>>"
  3.     price=66.66, 
  4.     PublishDate="2020-01-02"
  5.     comment_num=23, 
  6.     collect_num=12, 
  7.     # 外键字段 django models对应的mysql 为 字段_id 
  8.     publish_id=1, ) 
  9. book_obj.save() 

方式三,通过字典方式。

可能有的时候,我们正好将传过来的参数构造成了一个字典,那就太好了,不需要再一个个取。

  1. c_dict = { 
  2.     "title":"<<tcp编程从入门到精通2>>"
  3.     "price":88.1, 
  4.     "PublishDate":"2020-01-03"
  5.     "comment_num":13, 
  6.     "collect_num":78, 
  7.     "publish_id":1, 
  8. models.Book.objects.create(**c_dict) 

更新

:update只能跟在在filter之后。

示例:将title="<<大明帝国>>"的数据修改为title="<<大明帝国666>>"。

代码

  1. models.Book.objects.filter(title="<<大明帝国>>").update(title="<<大明帝国666>>"

filter可能筛选到的是多个值,一定要注意

删除

delete只能跟在filter之后。

示例:删除title=<<大明帝国666>>的数据。

  1. models.Book.objects.filter(title="<<大明帝国666>>").delete() 

总结

好了各位,到此为止,基本上,Django ORM操作基本完毕,至少80%的知识都覆盖完毕。

本篇主要补充的是一些高端操作,例如聚合操作,分组操作,分组再筛选操作,F查询和Q查询。

如何动态构造Q查询。

相对来说,Django还是自由度比价高的,而且写起来确实比较省心。

用微笑告诉别人,今天的我比昨天强,今后也一样。

 

责任编辑:姜华 来源: Python爬虫与数据挖掘
相关推荐

2020-12-29 09:05:48

基础DjangoORM

2021-01-01 09:20:20

操作DjangoORM

2021-01-12 09:04:12

Django FormForm组件开发

2021-06-30 00:20:12

Hangfire.NET平台

2023-05-12 08:19:12

Netty程序框架

2021-06-04 09:56:01

JavaScript 前端switch

2021-02-02 18:39:05

JavaScript

2020-11-10 10:48:10

JavaScript属性对象

2021-01-29 18:41:16

JavaScript函数语法

2021-03-09 14:04:01

JavaScriptCookie数据

2021-05-18 08:30:42

JavaScript 前端JavaScript时

2021-03-05 18:04:15

JavaScript循环代码

2021-01-26 23:46:32

JavaScript数据结构前端

2023-05-08 08:21:15

JavaNIO编程

2024-04-19 14:23:52

SwitchJavaScript开发

2023-09-06 14:57:46

JavaScript编程语言

2023-07-30 15:18:54

JavaScript属性

2021-09-27 09:18:30

ListIterato接口方法

2020-12-08 08:09:49

SVG图标Web

2024-01-30 13:47:45

点赞
收藏

51CTO技术栈公众号