在这里我根据是否支持链式调用分类进行介绍

1. 支持链式调用的接口

  • all

使用频率比较高,相当于SELECT * FROM table 语句,用于查询所有数据。

  • filter

使用频率比较高,根据条件过滤数据,常用的条件基本上字段等于、不等于、大于、小于。当然,还有其他的,比如能修改成产生LIKE查询的:Model.objects.filter(content__contains="条件")。

  • exclude

与filter是相反的逻辑

  • reverse

将QuerySet中的结果倒叙排列

  • distinct

用来进行去重查询,产生SELECT DISTINCT这样的SQL查询

  • none

返回空的QuerySet

2. 不支持链式调用的接口

  • get

比如Post.objects.get(id=1)用于查询id为1的文章:如果存在,则直接返回对应的Post实例;如果不存在,则抛出DoesNotExist异常。所以一般情况下,要使用异常捕获处理:

1 try:
2 post = Post.objects.get(id=1)
3 except Post.DoesNotExist:
4 #做异常情况处理
  • create

用来直接创建一个Model对象,比如post = Post.objects.create(title="一起学习")。

  • get_or_create

根据条件查找,如果没查找到,就调用create创建。

  • update_or_create

与get_or_create相同,只是用来做更新操作。

  • count

用于返回QuerySet有多少条记录,相当于SELECT COUNT(*) FROM table 。

  • latest

用于返回最新的一条记录,但要在Model的Meta中定义:get_latest_by= <用来排序的字段>。

  • earliest

同上,返回最早的一条记录。

  • first

从当前QuerySet记录中获取第一条。

  • last

同上,获取最后一条。

  • exists

返回True或者False,在数据库层面执行SELECT (1) AS "a" FROM table LIMIT 1的查询,如果只是需要判断QuerySet是否有数据,用这个接口是最合适的方式。

不要用count或者len(queryset)这样的操作来判断是否存在。相反,如果可以预期接下来会用到QuerySet中的数据,可以考虑使用len(queryset)的方式来做判断,这样可以减少一次DB查询请求。

  • bulk_create

同create,用来批量创建记录。

  • in_ bulk

批量查询,接收两个参数id_ list和filed_ name。可以通过Post.objects. in_ bulk([1, 2, 3])查询出id为1、2、3的数据,返回结果是字典类型,字典类型的key为查询条件。返回结果示例: {1: <Post 实例1>, 2: <Post实例2>,3:<Post实例3>}。

  • update

用来根据条件批量更新记录,比如: Post.objects.filter(owner__name='123').update(title='测试更新')。

  • delete

同update,这个接口是用来根据条件批量删除记录。需要注意的是,和delete都会触发Djiango的signal

  • values

当我们明确知道只需要返回某个字段的值,不需要Model实例时,用它,用法如下:

1 title_list = Post.objects.filter(category_id=1).values('title')

返回的结果包含dict的QuerySet,类似这样: <QuerySet [{'title' :xxx},]>

  • values_list

同values,但是直接返回的是包含tuple的QuerySet:

1 titles_list = Post.objects.filter(category=1).values_list('title')

返回结果类似: <QuerySet[("标题",)]>

如果只是一个字段的话,可以通过增加flat=True参数,便于我们后续 处理:

1 title_list = Post.objects.filter(category=1).values_list('title',flat=True)
2 for title in title__list:
3 print(title)

2.1进阶接口

除了上面介绍的常用接口外,还有其他用来提高性能的接口,在下面介绍。 在优化Django项目时,尤其要考虑这几种接口的用法。

  • defer

把不需要展示的字段做延迟加载。比如说,需要获取到文章中除正文外的其他字段,就可以通过posts = Post.objects.all() .defer('content'),这样拿到的记录中就不会包含content部分。但是当我们需要用到这个字段时,在使用时会去加载。代码:

1 posts = Post.objects.all().defer('content')
2 for post in posts: #此时会执行数据库查询
3 print (post.content) #此时会执行数据查询,获取到content

当不想加载某个过大的字段时(如text类型的字段),会使用defer,但是上面的演示代产生N+1的查询问题,在实际使用时千万要注意!

注意:上面的代码是个不太典型的 N+1查询的问题, 一般情况下 由外键查询产生的N+1问题比较多,即一条查询请求返回N条数据,当我们操作数据时,又会产生额外的请求。这就是N+1问题,所有的ORM框架都存在这样的问题。

  • only

同defer接口刚好相反, 如果只想获取到所有的title记录,就可以使用only,只获取title的内容,其他值在获取时会产生额外的查询。

  • select_related

这就是用来解决外键产生的N+1问题的方案。我们先来看看什么情况下会产生这个问题:

posts = Post.objects.all ()
for post in posts: #产生数据库查询
print (post.owner) #产生额外的数据库查询

代码同上面类似,只是这里用的是owenr(是关联表)。它的解决方法就是用select_ related接口:

post = Post.objects.all() .select_related('category')
for post in posts: # 产生数据库查询,category数据也会一次性查询出来
print (post.category)

当然,这个接口只能用来解决一对多的关联关系。对于多对多的关系,还得使用下面的接口。

  • prefetch_related

针对多对多关系的数据,可以通过这个接口来避免N+1查询。比如,post和tag的关系可以通过这种方式来避免:

posts = Post.objects.all().prefetch_related('tag')
for post in posts:#产生两条查询语句,分别查询post和tag
print(post.tag.al1())

3.常用的字段查询

  • contains

包含,用来进行相似查询。

  • icontains

同contains,只是忽略大小写。

  • exact

精确匹配。

  • iexact

同exact,忽略大小写。

  • in

指定某个集合,比如Post.objects.filter(id__in=[1, 2, 3])相当于SELECT FROM table WHERE IN (1, 2, 3);。

  • gt

大于某个值。比如:Post.objects.filter(id__gt=1)

注意:是__gt

  • gte

大于等于某个值。

  • lt

小于某个值。

  • lte

小于等于某个值。

  • startswith

以某个字符串开头,与contains类似,只是会产生LIKE '<关键词>%'这样的SQL。

  • istartswith

同startswith, 忽略大小写。

  • endswith

以某个字符串结尾。

  • iendswith

同endswith,忽略大小写。

  • range

范围查询,多用于时间范围,如Post.objects.filter(created_time__range= ('2018-05-01','2018-06-01'))会产生这样的查询: SELECT .. . WHERE created_ time BETWEEN '2018-05-01' AND '2018-06-01' ;。

关于日期类的查询还有很多,比如date、year和month等,具体等需要时查文档即可。

这里你需要理解的是,Django之所以提供这么多的字段查询,其原因是通过ORM来操作数据库无法做到像SQL的条件查询那么灵活。

因此,这些查询条件都是用来匹配对应SQL语句的,这意味着,如果你知道某个查询在SQL中如何实现,可以对应来看Django提供的接口。

3.1 进阶查询

除了上面基础的查询语句外,Django还提供了其他封装,来满足更复杂的查询,比如 SELECT ... WHERE id = 1 OR id = 2 这样的查询,用上面的基础查询就无法满足。

  • F

F表达式常用来执行数据库层面的计算,从而避免出现竞争状态。比如需要处理每篇文章的访问量,假设存在post.pv这样的字段,当有用户访问时,我们对其加1:

post = Post.objects.get(id=1)
post.pv = post.pv+1
post.save()

这在多线程的情况下会出现问题,其执行逻辑是先获取到当前的pv值,然后将其加1后赋值给post .pv.最后保存。

如果多个线程同时执行了post = Post.objects.get(id=1),那么每个线程里的post .pv值都是一样的, 执行完加1和保存之后,相当于只执行了一个加1,而不是多个。

这时通过F表达式就可以方便地解决这个问题:

from ajango.ab. models import F
post = Post.objects.get(id=1)
post.pv = F('pv') + 1
post.save():

这种方式最终会产生类似这样的SQL语句: UPDATE table SET pv = pv +1 WHERE ID = 1。 它在数据库层面执行原子性操作。

  • Q

Q表达式就是用来解决前面提到的那个OR查询的,可以这么用:

from django.db.mode1s import Q
Post.objects.filter(Q(id=1) | Q(id=2))

或者进行AND查询:

Post.objects.filter(Q(id=1) & Q(id=2))
  • Count

用来做聚合查询,比如想要得到某个分类下有多少篇文章,简单的做法就是:

category = Category.objects.get(id=1)
posts_count = category.post_set.count()

但是如果想要把这个结果放到category上呢?通过category.post_count可以访问到:

from django.db.models import Count
categories = Category.objects.annotate(posts_count=Count('post'))
print(categories[0].posts_count)

这相当于给category动态增加了属性post_count,而这个属性的值来源于Count('post'),最后可以用int取整。

  • Sum

同Count类似,只是它是用来做合计的。比如想要统计所有数据字段的总和,可以这么做:

from django.db.models import Sum
Post.objects.all().aggregate(a=Sum('字段'))
#输出类似结果:{'a':487}为字典

python中对字典中键值对的获取:

for i in book:
print(i)#键的获取
print(book[i])#值的获取

上面演示了QuerySet的annotate和aggregate的用法,其中前者用来給QuerySet结果増加属性,后者只用来直接计算结果,这些聚合表达式都可以与它们结合使用。

除了Count和Sum外,还有Avg、Min和Max等表达式,均用来满足我们对SQL査洵的需求。

Django常用的QuerySet操作的更多相关文章

  1. 【技术博客】MySQL和Django常用操作

    MySQL和Django是搭建网站常用的配置之一,在此记录一下在Windows系统搭建网站时MySQL以及Django常用的操作. MySQL MySQL的SQL语句不区分大小写,推荐将保留字大写,数 ...

  2. 【Django】Django model与数据库操作对应关系(转)

    Django对数据库的操作分用到三个类:Manager.QuerySet.Model. Manager的主要功能定义表级方法(表级方法就是影响一条或多条记录的方法),我们可以以models.Manag ...

  3. Python开发【Django】:Model操作(一)

    Django ORM基本配置 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去 ...

  4. Django 之models进阶操作

    到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 ...

  5. django 常用 详解

    Django 1 django框架介绍 是一个开源框架,2005年发布,采用Python语言编写的,早期时主要做新闻和内容管理的网站 Django本身提供了非常强大的后台管理系统 看中文说明文档 百度 ...

  6. Django中的模型(操作数据库)

    目录 Django配置连接数据库 在Django中操作数据库 原生SQL语句操作数据库 ORM模型操作数据库 增删改查 后台管理 使用后台管理数据库 模型是数据唯一而且准确的信息来源.它包含您正在储存 ...

  7. Django ORM 多表操作

    目录 Django ORM 多表操作 表模型 表关系 创建模型 逆向到表模型 插入数据 ORM 添加数据(添加外键) 一对多(外键 ForeignKey) 一对一 (OneToOneFeild) 多对 ...

  8. Python/Django(CBV/FBV/ORM操作)

    Python/Django(CBV/FBV/ORM操作) CBV:url对应的类(模式) ##====================================CBV操作============ ...

  9. Django学习之六:Django 常用模块导入记忆

    Django 常用模块导入记忆 django相关 1. urls相关操作 from django.urls import path, re_path, include from django.urls ...

随机推荐

  1. 《HelloGitHub》第 68 期

    兴趣是最好的老师,HelloGitHub 让你对编程感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. https://github.com/521xueweiha ...

  2. nginx配置8081端口异常

    1.为nginx配置8081端口,结果nginx报错. (nginx配置8081端口监听,通过查看日志,出现nginx: [emerg] bind() to 0.0.0.0:8081 failed ( ...

  3. 关于CSS的粘性定位sticky失效问题

    CSS的粘性定位sticky可以起到吸顶灯的作用,用法如下 <body> <div> <nav style="postion:sticky; top: 0;&q ...

  4. nodejs中的fs模块中的方法

    nodejs中的fs模块 引入模块 const fs =require("fs") 检测文件是否存在fs.stat(path,callback) fs.stat("./n ...

  5. bzoj4036 / P3175 [HAOI2015]按位或

    bzoj4036 / P3175 [HAOI2015]按位或 是一个 min-max容斥 的板子题. min-max容斥 式子: $ \displaystyle max(S) = \sum_{T\su ...

  6. GORM基本使用

    GORM 目录 GORM 1. 安装 2. 数据库连接 3. 数据库迁移及表操作 1. 安装 go get -u github.com/jinzhu/gorm 要连接数据库首先要导入驱动程序 // G ...

  7. 02 Windows安装C语言开发工具CodeBlocks

    CodeBlocks安装 使用微信扫码关注微信公众号,并回复:"C语言环境",免费获取下载链接! 1.卸载CodeBlocks(电脑未装此软件,跳过)    进入目录:C:\Pro ...

  8. 强化学习实战 | 自定义Gym环境之井字棋

    在文章 强化学习实战 | 自定义Gym环境 中 ,我们了解了一个简单的环境应该如何定义,并使用 print 简单地呈现了环境.在本文中,我们将学习自定义一个稍微复杂一点的环境--井字棋.回想一下井字棋 ...

  9. IDEA修改数据库信息,结果修改信息中文成 ?

    今天在用IDEA进行插入数据库信息时,发生了一件意想不到的事情,特意记录一下,方便后续查看: 就是我在IDEA的驱动文件中配置了useUnicode = true & characterEnc ...

  10. [C++] vptr, where are you?

    Search(c++在线运行). 有的网站很慢--不是下面的程序有问题. #include <string.h> #include <stdio.h> #include < ...