Django【执行查询】(一)

官方Django3.2 文档https://docs.djangoproject.com/en/3.2/topics/db/queries/
本文大部分内容参考官方3.2版本文档撰写,仅供学习使用
官方PDF 下载链接https://media.readthedocs.org/pdf/django/3.2.x/django.pdf

Django 执行查询(一)

(本文中涉及的到的代码,建议复制粘贴的会以可折叠代码块展示,其他代码块建议手动练习。如果你对Models没有初步认识,欢迎去看看官方文档-Models或者其他文章。)

初步准备

将参考以下模型,它们构成了一个 Weblog 应用程序,文章中所有查询操作都基于该模型。

点击查看代码

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

将修改保存到对象

使用模型类的关键字参数对其进行实例化,然后调用save()以将其保存到数据库中:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

检索对象

如果你想查看Queryset相关API,可以点击这个链接
为了从数据库中检索对象,通过你的模型类上的Manager(管理器)构造一个QuerySet。过滤器根据给定的参数缩小查询结果的范围。在SQL术语中,一个QuerySet相当于一个SELECT语句,而过滤器是一个限制性子句,如WHERE或LIMIT。
您可以使用模型的 Manager 获得一个 QuerySet。每个模型至少有一个Manager(管理器),默认称为objects。通过模型类直接访问它,如下所示:

>>> Blog.objects
<django.db.models.manager.manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
    ...

AttributeError: "Manager isn't accessible via Blog instances."
</django.db.models.manager.manager>

【注意】

管理器(manger)只能通过模型类而不是 模型实例 来访问,以强制区分”表级”操作和”记录级”操作。

Manager(管理器) 是模型的 QuerySet 的主要来源。例如,Blog.objects.all() 返回一个包含数据库中所有 Blog 对象的 QuerySet。

检索所有对象

从表中检索对象的最简单方法是获取所有对象。为此,请在 Manager 上使用 all() 方法:

>>> all_entries = Entry.objects.all()

all() 方法返回了数据库中所有对象的 QuerySet。

使用过滤器检索特定对象

all() 返回的 QuerySet 描述了数据库表中的所有对象。但是,通常您只需要选择完整对象集的一个子集。
要创建这样的子集,您需要优化初始 QuerySet,添加过滤条件。细化 QuerySet 的两种最常见的方法是:

filter(**kwargs)

返回一个新的 QuerySet,其中包含与给定查找参数匹配的对象。

exclude(**kwargs)

返回一个新的 QuerySet,其中包含与给定查找参数匹配的对象。

返回一个新的QuerySet,包含不符合给定查找参数的对象。
查询参数(上述函数定义中的**kwargs)应该采用下面字段查询中描述的格式。
例如,要包含获取 2006 年的博客条目(entries blog)的 QuerySet,像这样使用 filter():

Entry.objects.filter(pub_date__year=2006)
通过默认管理器类也一样:

Entry.objects.all().filter(pub_date__year=2006)

链式过滤器

细化QuerySet 的结果本身还是一个 QuerySet,所以能串联多个细化过程。例子:

 >>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.date.today()
... ).filter(
...     pub_date__gte=datetime.date(2005, 1, 30)
... )

这个例子先获取包含数据库所有条目(entry)的 QuerySet,添加一个过滤器,然后排除一些,再进入另一个过滤器。最终的 QuerySet 包含标题以 “What” 开头的,发布日期介于 2005 年 1 月 30 日与今天之间的所有条目。

每个Queryset都是唯一的

每次精炼(细化)一个 QuerySet,你就会获得一个全新的 QuerySet,后者与前者毫无关联。每次精炼都会创建一个单独的、不同的 QuerySet,能被存储,使用和复用。

>>> q1 = Entry.objects.filter(headline__startswith="What")
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today())

这三个 QuerySets 是独立的。第一个是基础 QuerySet,包含了所有标题以 “What” 开头的条目。第二个是第一个的子集,带有额外条件,排除了 pub_date 是今天和今天之后的所有记录。第三个是第一个的子集,带有额外条件,只筛选 pub_date 是今天或未来的所有记录。最初的 QuerySet (q1) 不受筛选操作影响。

QuerySet 是惰性的

QuerySet 是惰性的 —— 创建 QuerySet 并不会引发任何数据库活动。你可以将一整天的过滤器都堆积在一起,Django 只会在 QuerySet 被计算时执行查询操作。来瞄一眼这个例子:

>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.date.today())
>>> q = q.exclude(body_text__icontains="food")
>>> print(q)

虽然这看起来像是三次数据库操作,实际上只在最后一行 (print(q)) 做了一次。一般来说, QuerySet 的结果直到你 “要使用” 时才会从数据库中拿出。当你要用时,才通过数据库计算出 QuerySet。

用 get() 检索单个对象

filter() 总是返回一个 QuerySet,即便只有一个对象满足查询条件 —— 这种情况下,QuerySet 只包含了一个元素。

若你知道只会有一个对象满足查询条件,你可以在 Manager 上使用 get() 方法,它会直接返回这个对象:
>>> one_entry = Entry.objects.get(pk=1)

【注意】

使用切片 [0] 时的 get() 和 filter() 有点不同。如果没有满足查询条件的结果, get() 会抛出一个 DoesNotExist 异常。该异常是执行查询的模型类的一个属性 —— 所有,上述代码中,若没有哪个 Entry 对象的主键是 1,Django 会抛出 Entry.DoesNotExist。

类似了,Django 会在有不止一个记录满足 get() 查询条件时发出警告。这时,Django 会抛出 MultipleObjectsReturned,这同样也是模型类的一个属性。

所以说get()方法的使用中无论不存在或者存在多条都会报错,抛出的异常是可以被合理应用的

其它 QuerySet 方法

大多数情况下,你会在需要从数据库中检索对象时使用 all(), get(), filter() 和 exclude()。然而,这样远远不够;完整的各种 QuerySet 方法请参阅 QuerySet API reference

限制Queryset条目数

总结一下,可以切边,切边后的结果不能再排序or过滤。而且不能使用副索引

利用 Python 的数组切片语法将 QuerySet 切成指定长度。这等价于 SQL 的 LIMIT 和 OFFSET 子句。

例如,这将返回前 5 个对象 (LIMIT 5):

>>> Entry.objects.all()[:5]

这会返回第 6 至第 10 个对象 (OFFSET 5 LIMIT 5):

>>> Entry.objects.all()[5:10]

不支持负索引 (例如 Entry.objects.all()[-1])

一般情况下, QuerySet 的切片返回一个新的 QuerySet —— 其并未执行查询。一个特殊情况是使用了的 Python 切片语法的 “步长”。例如,这将会实际的执行查询命令,为了获取从前 10 个对象中,每隔一个抽取的对象组成的列表:

>>> Entry.objects.all()[:10:2]

由于对 queryset 切片工作方式的模糊性,禁止对其进行进一步的排序或过滤。

要检索 单个 对象而不是一个列表时(例如 SELECT foo FROM bar LIMIT 1),请使用索引,而不是切片。例如,这会返回按标题字母排序后的第一个 Entry:

>>> Entry.objects.order_by('headline')[0]

这大致等价于:

>>> Entry.objects.order_by('headline')[0:1].get()

然而,注意一下,若没有对象满足给定条件,前者会抛出 IndexError,而后者会抛出 DoesNotExist。参考 get() 获取更多细节。

字段查询

字段查询即你如何制定 SQL WHERE 子句。它们以关键字参数的形式传递给 QuerySet 方法 filter(), exclude() 和 get()。

基本的查询关键字参数遵照 field__lookuptype=value。(有个双下划线)。例如:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')

转换为 SQL 语句大致如下:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';< code><!--=-->

查询子句中指定的字段必须是模型的一个字段名。不过也有个例外,在 ForeignKey 中,你可以指定以 _id 为后缀的字段名。这种情况下,value 参数需要包含 foreign 模型的主键的原始值。例子:
(点击此连接 ForeignKey 官方详解(多对一关系))

>>> Entry.objects.filter(blog_id=4)

若你传入了无效的关键字参数,查询函数会抛出 TypeError。

数据库 API 支持两套查询类型;完整参考文档位于 QuerySet API reference 字段查询参考。为了让你了解能干啥,以下是一些常见的查询:

exact

完全匹配。如果提供的比较值是 None,它将被解释为 SQL NULL (详见 isnull)。

一个 “exact” 匹配的例子:

>>> Entry.objects.get(headline__exact="Cat bites dog")
官方翻译:
若你没有提供查询类型 —— 也就说,若关键字参数未包含双下划线 —— 查询类型会被指定为 exact。
google翻译:
如果您不提供查找类型(即,如果您的关键字参数不包含双下划线),则假定查找类型是exact(精确)。
(下图为官方翻译,我觉得有点问题)

[En]

(the following picture is an official translation, which I think is a bit of a problem)

Django【执行查询】(一)

iexact

不区分大小写的完全匹配。如果提供的比较值是 None,它将被解释为 SQL NULL (详见 isnull)。

>>> Blog.objects.get(name__iexact="beatles blog")

会匹配标题为 “Beatles Blog”, “beatles blog”, 甚至 “BeAtlES blOG” 的 Blog。

contains

区分大小写的包含测试。

举例:

Entry.objects.get(headline__contains='Lennon')

SQL 等价于:

SELECT ... WHERE headline LIKE '%Lennon%';

icontains

不区分大小写的包含测试。

[En]

Case-insensitive inclusion tests.

举例:

Entry.objects.get(headline__icontains='Lennon')

SQL 等价于:

SELECT ... WHERE headline ILIKE '%Lennon%';

startswith, endswith

区分大小写的开头为;区分大小写的结尾为.

以……开头和以……结尾的查找。当然也有大小写不敏感的版本,名为 istartswith 和 iendswith。

(官方文档中对 field 查询参考 没有再详细介绍,对更多字段查询感兴趣可以查看我google翻译的文章,点击这段话即可)

跨关系查询

Django 提供了一种强大而直观的方式来”追踪”查询中的关系,在幕后自动为你处理 SQL JOIN 关系。为了跨越关系,跨模型使用关联字段名,字段名由双下划线分割,直到拿到想要的字段。

本例检索出所有的 Entry 对象,其 Blog 的 name 为 ‘Beatles Blog’ :

>>> Entry.objects.filter(blog__name='Beatles Blog')

此跨距可以是您想要的深度。

[En]

This span can be the depth you want.

它也可以反向工作。尽管可以对其进行定制,但默认情况下,您在查询中使用模型的小写名称来引用“反向”关系。

[En]

It can also work backwards. Although it can be customized, by default, you use the lowercase name of the model in the query to refer to the “reverse” relationship.

本例检索的所有 Blog 对象均拥有少一个 标题 含有 ‘Lennon’ 的条目:

>>> Blog.objects.filter(entry__headline__contains='Lennon')

Original: https://www.cnblogs.com/libai1024/p/Django_queries_1.html
Author: libai1024
Title: Django【执行查询】(一)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/499139/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • NTP网络授时服务器(NTP服务器)助力智慧城市网络系统

    NTP网络授时服务器(NTP服务器)助力智慧城市网络系统 京准电子科技 官微——ahjzsz 智慧城市建设行动框架为:一个”城市大脑”、一个数据资源中心、一…

    Python 2023年10月24日
    040
  • 手把手教你用python实现机器学习预测疾病

    电子存储的医疗成像数据非常丰富,机器学习算法可以使用这种类型的数据集来检测和发现模式和异常。在本文中,我将向您介绍五个医疗保健领域的机器学习项目。机器和算法可以解读成像数据,就像受…

    Python 2023年8月2日
    099
  • numpy的基本操作

    文章目录 有关numpy的基本操作 * numpy 有关dim shape dtype 属性 有关sum函数 矢量化运算 创建数组函数: 元素级数组函数 – 一元函数 …

    Python 2023年8月24日
    041
  • (原创、不是重复文章)xxx GiB reserved in total by PyTorch的问题

    RuntimeError: CUDA out of memory. Tried to allocate 72.00 MiB (GPU 0; 4.00 GiB total capac…

    Python 2023年8月2日
    071
  • python断言异常类名_在pytest中,如果异常(从父异常类继承)被引发,如何断言?…

    ### 回答1: Servlet的init()方法是在Servlet被容器加载时自动调用的方法,如果该方法 引发 异常,则说明在Servlet初始化过程 中_出现了问题。 常见的原…

    Python 2023年9月14日
    046
  • wordcloud库详解

    wordcloud库是优秀的词云展示第三方库,可以将一段文本变成词云(词云以词语为基本单位,更加直观和艺术的展示文本) cmd命令行 pip install wordcloud 示…

    Python 2023年8月1日
    068
  • python模块

    python模块是一个py文件,一个模块只会被导入一次 python在编译或安装的时候会确定搜索路径,使用import语句的时候,python解释器就从搜索路径(即一系列目录名)中…

    Python 2023年11月3日
    039
  • 基于ServiceStage的微服务开发与部署(二)

    2.3. 微服务接入CSE 步骤 1 打开”应用管理与运维平台”-“基础设施”-“微服务引擎(CSE)”,查…

    Python 2023年10月9日
    036
  • supervisor的安装与使用

    Ubuntu安装使用supervisor 进程管理工具 安装 apt-get install supervisor 查看是否安装成功 pgrep supervisord 返回进程号…

    Python 2023年6月12日
    061
  • OS 模块介绍

    一、简介 os模块是Python内置的模块,它提供了多种操作系统的接口。通过os模块提供的操作系统接口,我们可以对操作系统里文件、终端、进程等进行操作。 先附上官方文档的链接,有兴…

    Python 2023年8月23日
    063
  • Pandas数据分析17——pandas数据清洗(缺失值、重复值处理)

    参考书目:《深入浅出Pandas:利用Python进行数据处理与分析》 pandas对大数据有很多便捷的清洗用法,尤其针对缺失值和重复值。缺失值就不用说了,会影响计算,重复值有时候…

    Python 2023年8月23日
    068
  • python爬虫-scrapy的数据持久化存储

    文章目录 一、基于终端指令的持久化存储 二、基于管道的持久化存储 一、基于终端指令的持久化存储 目的:爬取百度网页中百度热榜中的 序号和标题,并通过终端指令,将爬取到的数据进行持久…

    Python 2023年10月5日
    034
  • Pandas的主要数学计算方法

    可用于Series和DataFrame df = pd.DataFrame({‘key1’:np.arange(10), ‘key2’:np.random.rand(10)*10}…

    Python 2023年8月7日
    048
  • conda 创建环境及运用

    终究是被现实击溃了!本来想着这种版本问题在本机上多配几个不同版本的 python 切换就完了,但是膜拜大佬的科研成果的同时又无法解决不同版本包的适配问题后,终究是顶不住了。没办法,…

    Python 2023年9月7日
    031
  • pycharm Gitee配置

    一、 win10 git已安装但右键不显示图标解决方案 Win + R弹出命令行输入:regedit弹出注册表 在注册表:计算机\HKEY_CLASSES_ROOT\Directo…

    Python 2023年8月4日
    054
  • 测试平台开发:(12)Django登录功能

    上一篇:测试平台开发:(11)Django跨域和时区问题_sinat_23377479的博客-CSDN博客 实现了注册功能,开始登录功能。同样,输入正确的用户名和密码即可登录成功。…

    Python 2023年8月4日
    062
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球