QuerySet API引用

本文档描述了 QuerySet 应用程序编程接口。它建立在 modeldatabase query 指南,所以在阅读本文之前,您可能需要阅读和理解这些文档。

在本参考中,我们将使用 example blog modelsdatabase query guide

什么时候? QuerySet s被评估

内部,A QuerySet 可以构造、过滤、切片和传递,而实际上不需要访问数据库。在对查询集进行计算之前,实际上不会发生数据库活动。

您可以评估 QuerySet 方法如下:

  • 迭代。 A QuerySet 它是可重复的,并且在您第一次迭代它时执行它的数据库查询。例如,这将打印数据库中所有条目的标题:

    for e in Entry.objects.all():
        print(e.headline)
    

    注意:如果您只想确定是否存在至少一个结果,则不要使用此选项。使用起来更有效 exists() .

  • Asynchronous iteration. A QuerySet 也可以使用 async for **

    async for e in Entry.objects.all():
        results.append(e)
    

    QuerySet的同步和异步迭代器共享相同的底层缓存。

  • 切片。 正如在 限制 QuerySet 的S ,A QuerySet 可以使用Python的数组切片语法进行切片。切片未估价的 QuerySet 通常返回另一个未估值的 QuerySet 但如果使用slice语法的“step”参数,django将执行数据库查询,并返回一个列表。切片A QuerySet 已评估的还返回一个列表。

    还要注意的是,即使切片时 QuerySet 返回另一个未估值的 QuerySet 不允许进一步修改它(例如添加更多的过滤器或修改排序),因为这不能很好地转换为SQL,而且也没有明确的含义。

  • Pickling/Caching. 请参阅以下部分,了解在以下情况下涉及的详细信息: pickling QuerySets . 对于本节而言,重要的是从数据库中读取结果。

  • repr(). A QuerySet 在您调用时进行评估 repr() 关于它。这是为了方便在Python交互式解释器中使用,因此当以交互方式使用API时,您可以立即看到结果。

  • Le()。 A QuerySet 在您调用时进行评估 len() 关于它。如您所料,这将返回结果列表的长度。

    注意:如果您只需要确定集合中的记录数(而不需要实际的对象),那么使用SQL在数据库级别处理计数会更有效。 SELECT COUNT(*) . Django提供了 count() 正是因为这个原因。

  • list()。 A的力评估 QuerySet 通过调用 list() 关于它。例如::

    entry_list = list(Entry.objects.all())
    
  • bool()。 测试A QuerySet 在布尔上下文中,例如使用 bool()orandif 语句,将导致执行查询。如果至少有一个结果, QuerySetTrue ,否则 False . 例如::

    if Entry.objects.filter(headline="Test"):
        print("There is at least one Entry with the headline Test")
    

    注意:如果您只想确定是否存在至少一个结果(并且不需要实际的对象),那么使用它更有效 exists() .

酸洗 QuerySet 的S

如果你 pickleQuerySet ,这将强制在酸洗之前将所有结果加载到内存中。pickle通常用作缓存的前兆,当重新加载缓存的查询集时,您希望结果已经存在并可以使用(从数据库读取可能需要一些时间,从而破坏了缓存的目的)。这意味着当你拆开 QuerySet ,它包含被pickle时的结果,而不是当前在数据库中的结果。

如果您只想保留必要的信息以重新创建 QuerySet 以后从数据库中,将 query 属性的属性 QuerySet 。然后,您可以重新创建原始 QuerySet (未加载任何结果)使用如下代码:

>>> import pickle
>>> query = pickle.loads(s)  # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query  # Restore the original 'query'.

这个 query 属性是不透明对象。它表示查询构造的内部,不是公共API的一部分。但是,可以安全地(并且完全支持)pickle和unpickle属性的内容,如本文所述。

限制 QuerySet.values_list()

如果您重新创建 QuerySet.values_list() 使用腌制的 query 属性,则它将被转换为 QuerySet.values()

>>> import pickle
>>> qs = Blog.objects.values_list("id", "name")
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
>>> reloaded_qs.query = pickle.loads(pickle.dumps(qs.query))
>>> reloaded_qs
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

您不能在不同版本之间共享pickle

Pickles QuerySets 仅对用于生成它们的Django版本有效。如果使用django版本n生成pickle,则无法保证pickle可以与django版本n+1一起读取。泡菜不应该作为长期存档策略的一部分。

由于pickle兼容性错误很难诊断,例如静默损坏的对象, RuntimeWarning 当您尝试在Django版本中取消拾取与该版本不同的查询集时引发。

QuerySet API

这是A的正式声明 QuerySet

class QuerySet(model=None, query=None, using=None, hints=None)[源代码]

通常当你将与 QuerySet 您将在之前使用它 chaining filters . 最重要的是 QuerySet 方法返回新的查询集。本节后面将详细介绍这些方法。

这个 QuerySet 类具有以下可用于自省的公共属性:

ordered

True 如果 QuerySet 已订购-即 order_by() 子句或模型上的默认排序。 False 否则。

db

如果现在执行此查询,将使用的数据库。

备注

这个 query 参数到 QuerySet 存在,以便专用查询子类可以重建内部查询状态。参数的值是该查询状态的不透明表示,并且不是公共API的一部分。

返回新的方法 QuerySet 的S

Django提供了一系列 QuerySet 修改由返回的结果类型的优化方法 QuerySet 或者其SQL查询的执行方式。

备注

These methods do not run database queries, therefore they are safe to run in asynchronous code, and do not have separate asynchronous versions.

filter()

filter(*args, **kwargs)

返回新的 QuerySet 包含与给定查找参数匹配的对象。

查找参数 (**kwargs )应采用中描述的格式 Field lookups 下面。通过连接多个参数 AND 在基础SQL语句中。

If you need to execute more complex queries (for example, queries with OR statements), you can use Q objects (*args).

exclude()

exclude(*args, **kwargs)

返回新的 QuerySet 包含执行此操作的对象 not 匹配给定的查找参数。

查找参数 (**kwargs )应采用中描述的格式 Field lookups 下面。通过连接多个参数 AND 在底层的SQL语句中,整个内容都包含在 NOT() .

此示例排除 pub_date 大于2005-1-3,且 headline 是“你好”:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline="Hello")

在SQL术语中,计算结果为:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

此示例排除 pub_date 晚于2005-1-3或标题为“你好”::

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline="Hello")

在SQL术语中,计算结果为:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

注意,第二个例子更具限制性。

If you need to execute more complex queries (for example, queries with OR statements), you can use Q objects (*args).

annotate()

annotate(*args, **kwargs)

注释中的每个对象 QuerySet 随附清单 query expressions . 表达式可以是一个简单的值、对模型(或任何相关模型)上的字段的引用,或对与中的对象相关的对象计算的聚合表达式(平均值、和等)。 QuerySet .

每个参数 annotate() 是将添加到 QuerySet 这是退回的。

Django提供的聚合函数在 Aggregation Functions 下面。

使用关键字参数指定的批注将使用关键字作为批注的别名。匿名参数将根据聚合函数的名称和要聚合的模型字段为其生成别名。只有引用单个字段的聚合表达式才能是匿名参数。其他所有内容都必须是关键字参数。

例如,如果您正在操作博客列表,则可能需要确定每个博客中创建了多少条目:

>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

这个 Blog 模型没有定义 entry__count 属性本身,但通过使用关键字参数指定聚合函数,您可以控制批注的名称:

>>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

有关聚合的深入讨论,请参见 the topic guide on Aggregation .

alias()

alias(*args, **kwargs)

等同于 annotate() ,而不是在 QuerySet ,保存表达式以便以后与其他表达式一起重用 QuerySet 方法。当不需要表达式本身的结果,但它用于过滤、排序或作为复杂表达式的一部分时,这很有用。不选择未使用的值将从数据库中删除多余的工作,这将导致更好的性能。

例如,如果要查找条目超过5个的博客,但对条目的确切数量不感兴趣,则可以执行以下操作:

>>> from django.db.models import Count
>>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)

alias() 可与 annotate()exclude()filter()order_by()update() . 将别名表达式与其他方法(例如。 aggregate() ),必须将其升级为批注:

Blog.objects.alias(entries=Count("entry")).annotate(
    entries=F("entries"),
).aggregate(Sum("entries"))

filter()order_by() 可以直接获取表达式,但表达式的构造和用法通常不在同一位置发生(例如, QuerySet 方法创建表达式,供以后在视图中使用)。 alias() 允许以增量方式构建复杂表达式,可能跨越多个方法和模块,通过其别名引用表达式部分,并且仅使用 annotate() 最后的结果。

order_by()

order_by(*fields)

默认情况下,结果由 QuerySet 是按照 ordering 模型中的选项 Meta . 您可以使用 order_by 方法。

例子::

Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")

以上结果将由 pub_date 降序,然后按 headline 提升。前面的负号 "-pub_date" 指示 下降的 秩序。升序是隐含的。要随机订购,请使用 "?" ,像这样::

Entry.objects.order_by("?")

注: order_by('?') 根据您使用的数据库后端,查询可能既昂贵又缓慢。

要按不同模型中的字段排序,请使用与跨模型关系查询时相同的语法。即,字段的名称,后跟双下划线 (__ ,然后是新模型中字段的名称,等等,对于您想要加入的任意多个模型。例如::

Entry.objects.order_by("blog__name", "headline")

如果您试图按与另一个模型相关的字段排序,Django将在相关模型上使用默认排序,如果没有,则按相关模型的主键排序。 Meta.ordering 明确规定。例如,由于 Blog 模型未指定默认顺序::

Entry.objects.order_by("blog")

…与以下内容相同:

Entry.objects.order_by("blog__id")

如果 Blogordering = ['name'] ,则第一个查询集将与以下内容相同:

Entry.objects.order_by("blog__name")

您也可以订购 query expressions 通过调用 asc()desc() 在表达式上:

Entry.objects.order_by(Coalesce("summary", "headline").desc())

asc()desc() 有参数 (nulls_firstnulls_last )它控制如何对空值排序。

如果您还使用 distinct() . 见注释 distinct() 有关相关模型排序如何更改预期结果的说明。

备注

允许指定一个多值字段来排序结果(例如, ManyToManyField 字段,或 ForeignKey 字段)。

考虑这种情况:

class Event(Model):
    parent = models.ForeignKey(
        "self",
        on_delete=models.CASCADE,
        related_name="children",
    )
    date = models.DateField()


Event.objects.order_by("children__date")

在这里,每个订单可能有多个订购数据 Event 每个 Event 具有多重 children 将多次返回到新的 QuerySet 那个 order_by() 创造。换句话说,使用 order_by()QuerySet 返回的项可能多于您开始处理的项-这可能既不是预期的也不是有用的。

因此,在使用多值字段排序结果时要小心。 If 您可以确保对于您要订购的每一项,只有一个订购数据块,这种方法不应该出现问题。如果没有,请确保结果符合您的预期。

无法指定排序是否区分大小写。在区分大小写方面,Django将订购结果,但数据库后端通常会订购结果。

您可以按转换为小写的字段排序 Lower 这将实现案例一致性排序:

Entry.objects.order_by(Lower("headline").desc())

如果不希望对查询应用任何排序,甚至不希望对默认排序,请调用 order_by() 没有参数。

您可以通过检查 QuerySet.ordered 属性,将 True 如果 QuerySet 以任何方式订购。

order_by() 调用将清除以前的任何订购。例如,此查询将按 pub_date 而不是 headline ::

Entry.objects.order_by("headline").order_by("pub_date")

警告

订购不是免费操作。添加到排序中的每个字段都会给数据库带来成本。您添加的每个外键也将隐式包含其所有默认顺序。

如果查询没有指定顺序,则从数据库中以未指定的顺序返回结果。只有当通过一组字段对结果中的每个对象进行唯一标识时,才能保证特定的排序。例如,如果 name 字段不是唯一的,按它排序并不能保证具有相同名称的对象总是以相同的顺序出现。

reverse()

reverse()

使用 reverse() 方法反转返回查询集元素的顺序。调用 reverse() 第二次将顺序恢复到正常方向。

要检索查询集中的“最后”五个项目,可以执行以下操作:

my_queryset.reverse()[:5]

请注意,这与在python中从序列末尾进行切片不同。上面的示例将首先返回最后一个项,然后返回倒数第二个项,依此类推。如果我们有一个python序列 seq[-5:] 我们先看看最后的第五项。Django不支持这种访问模式(从末尾进行切片),因为在SQL中不可能有效地进行此操作。

另外,请注意 reverse() 通常只应在 QuerySet 具有已定义的顺序(例如,在查询定义默认顺序的模型时,或在使用 order_by() )如果没有为给定的 QuerySet 呼唤 reverse() 对它没有实际效果(调用之前未定义排序) reverse() ,之后将保持未定义)。

distinct()

distinct(*fields)

返回新的 QuerySet 使用的 SELECT DISTINCT 在其SQL查询中。这将从查询结果中删除重复的行。

默认情况下,A QuerySet 不会消除重复行。实际上,这很少是一个问题,因为简单的查询如 Blog.objects.all() 不要引入重复结果行的可能性。但是,如果查询跨越多个表,则当 QuerySet 进行评价。那是你使用的时候 distinct() .

备注

中使用的任何字段 order_by() SQL中包含调用 SELECT 柱。当与 distinct() . 如果按相关模型中的字段排序,则这些字段将添加到所选列中,否则,它们可能会使重复的行显示为不同的行。由于额外的列不会出现在返回的结果中(它们只是为了支持排序),因此有时看起来返回的结果不明显。

同样,如果使用 values() 查询以限制所选列,任何 order_by() (或默认模型排序)仍将涉及,可能会影响结果的唯一性。

这里的寓意是如果你使用 distinct() 注意按相关型号订购。同样,使用时 distinct()values() 同时,在按不在 values() 调用。

仅在PostgreSQL上,可以传递位置参数 (*fields )为了指定字段的名称, DISTINCT 应适用。这转化为 SELECT DISTINCT ON SQL查询。这就是区别。正常情况下 distinct() 调用,数据库比较 each 确定哪些行不同时,每行中的字段。对于一个 distinct() 使用指定的字段名调用,数据库将只比较指定的字段名。

备注

当指定字段名时, must 提供一个 order_by()QuerySet 以及 order_by() 必须以中的字段开始 distinct() ,顺序相同。

例如, SELECT DISTINCT ON (a) 为列中的每个值提供第一行 a . 如果不指定顺序,将得到一些任意行。

示例(第一个之后的示例仅适用于PostgreSQL):

>>> Author.objects.distinct()
[...]

>>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]

>>> Entry.objects.order_by("blog").distinct("blog")
[...]

>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]

>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]

>>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]

备注

记住 order_by() 使用已定义的任何默认相关模型排序。你可能必须明确地按关系排序 _id 或引用字段以确保 DISTINCT ON 表达式与 ORDER BY 条款。例如,如果 Blog 模型定义了 ordering 通过 name ::

Entry.objects.order_by("blog").distinct("blog")

…不起作用,因为查询将由 blog__name 因此与 DISTINCT ON 表达式。你必须明确地按关系排序 _id 领域 (blog_id 在这种情况下)或引用的 (blog__pk )以确保两个表达式匹配。

values()

values(*fields, **expressions)

返回A QuerySet 当用作iterable时,返回字典而不是模型实例。

这些字典中的每一个都代表一个对象,键与模型对象的属性名相对应。

此示例比较了 values() 使用普通模型对象:

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

这个 values() 方法接受可选的位置参数, *fields ,指定字段名 SELECT 应该是有限的。如果指定字段,则每个字典将仅包含指定字段的字段键/值。如果不指定字段,则每个字典将包含数据库表中每个字段的键和值。

示例:

>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

这个 values() 方法还接受可选的关键字参数, **expressions ,它们被传递到 annotate()

>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>

您可以使用内置和 custom lookups 在订购中。例如:

>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
>>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>

中的聚合。 values() 子句在同一 values() 第。条。如果需要按其他值分组,请将其添加到较早的 values() 而不是子句。例如:

>>> from django.db.models import Count
>>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
>>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>

值得一提的几个微妙之处:

  • 如果你有一个叫做 foo 那是一个 ForeignKey ,默认的 values() 调用将返回一个名为 foo_id ,因为这是存储实际值的隐藏模型属性的名称 foo 属性引用相关模型)。当你调用的时候 values() 输入字段名,可以输入 foofoo_id 您将得到相同的结果(字典键将与您传入的字段名匹配)。

    例如:

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    
    >>> Entry.objects.values("blog")
    <QuerySet [{'blog': 1}, ...]>
    
    >>> Entry.objects.values("blog_id")
    <QuerySet [{'blog_id': 1}, ...]>
    
  • 使用时 values()distinct() 注意,排序会影响结果。见注释 distinct() 有关详细信息。

  • 如果你使用 values() 后继条款 extra() 调用,由 select 论证中 extra() 必须明确包括在 values() 调用。任何 extra() A之后拨打的调用 values() 调用将忽略其多余的选定字段。

  • 调用 only()defer() 之后 values() 不合理,这样做会提高 TypeError .

  • 组合转换和聚合需要使用两个 annotate() 调用,显式调用或作为关键字参数调用 values() 。如上所述,如果已在相关字段上注册了转换,则第一个 annotate() 可以省略,因此以下示例是等效的:

    >>> from django.db.models import CharField, Count
    >>> from django.db.models.functions import Lower
    >>> CharField.register_lookup(Lower)
    >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry"))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate(
    ...     entries=Count("entry")
    ... )
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values(
    ...     "entry__authors__name__lower"
    ... ).annotate(entries=Count("entry"))
    <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
    

当您知道只需要少量可用字段中的值,并且不需要模型实例对象的功能时,它是有用的。只选择需要使用的字段更有效。

最后,注意你可以调用 filter()order_by() 等等,在 values() 调用,这意味着这两个调用是相同的:

Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()

使Django成为主流的人更喜欢把所有影响SQL的方法放在第一位,然后(可选地)放在任何影响输出的方法之后(例如 values() 但这并不重要。这是你炫耀个人主义的机会。

您还可以通过以下方式引用具有反向关系的相关模型上的字段 OneToOneFieldForeignKeyManyToManyField 属性:

>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
     {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>

警告

因为 ManyToManyField 属性和反向关系可以有多个相关行,包括这些行可以对结果集的大小产生乘数效应。如果您在 values() 查询,在这种情况下,将返回所有可能的组合。

的特殊值 JSONField 在SQLite上

由于这种方式, JSON_EXTRACTJSON_TYPE SQL函数是在SQLite上实现的,缺乏 BOOLEAN 数据类型, values() 会回来的 TrueFalse ,以及 None 而不是 "true""false" ,以及 "null" 的字符串 JSONField 关键点变换。

values_list()

values_list(*fields, flat=False, named=False)

这类似于 values() 唯一不同的是,它在迭代时返回元组,而不是返回字典。每个元组都包含传递到 values_list() Call-因此第一项是第一个字段,等等。例如:

>>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>

如果只传入单个字段,则还可以传入 flat 参数。如果 True ,这将意味着返回的结果是单值,而不是1元组。举个例子应该能更清楚地说明其中的区别:

>>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>

>>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>

传进来是个错误 flat 当有多个字段时。

你可以过去了 named=True 要将结果作为 namedtuple()

>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>

使用命名元组可能会使结果更具可读性,但会对将结果转换为命名元组造成较小的性能损失。

如果您不将任何值传递给 values_list() ,它将按声明的顺序返回模型中的所有字段。

一种常见的需求是获取某个模型实例的特定字段值。要实现这一点,请使用 values_list() 后跟一个 get() 致电:

>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'

values()values_list() 它们都是针对特定用例的优化:检索数据子集,而不需要创建模型实例的开销。当处理多对多和其他多值关系(例如反向外键的一对多关系)时,这个比喻就分崩离析了,因为“一行,一个对象”假设不成立。

例如,请注意在 ManyToManyField

>>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
 ('George Orwell', 'Why Socialists Do Not Believe in Fun'),
 ('George Orwell', 'In Defence of English Cooking'),
 ('Don Quixote', None)]>

具有多个条目的作者出现多次,没有任何条目的作者出现多次 None 对于条目标题。

同样,在查询反向外键时, None 对于没有任何作者的条目显示:

>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>

的特殊值 JSONField 在SQLite上

由于这种方式, JSON_EXTRACTJSON_TYPE SQL函数是在SQLite上实现的,缺乏 BOOLEAN 数据类型, values_list() 会回来的 TrueFalse ,以及 None 而不是 "true""false" ,以及 "null" 的字符串 JSONField 关键点变换。

dates()

dates(field, kind, order='ASC')

返回A QuerySet 它的计算结果是 datetime.date 对象的内容中表示特定类型的所有可用日期 QuerySet .

field 应该是 DateField 你的模型。 kind 应该是 "year""month""week""day" .每个 datetime.date 结果列表中的对象被“截断”到给定的 type .

  • "year" 返回字段的所有不同年份值的列表。

  • "month" 返回该字段所有不同的年/月值的列表。

  • "week" 返回该字段所有不同的年/周值的列表。所有日期都是星期一。

  • "day" 返回该字段的所有不同的年/月/日值的列表。

order ,默认为 'ASC' ,应该是 'ASC''DESC' . 这指定了如何排序结果。

例如:

>>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
>>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]

datetimes()

datetimes(field_name, kind, order='ASC', tzinfo=None)

返回A QuerySet 它的计算结果是 datetime.datetime 对象的内容中表示特定类型的所有可用日期 QuerySet .

field_name 应该是 DateTimeField 你的模型。

kind 应该是 "year""month""week""day""hour""minute""second" .每个 datetime.datetime 结果列表中的对象被“截断”到给定的 type .

order ,默认为 'ASC' ,应该是 'ASC''DESC' . 这指定了如何排序结果。

tzinfo 定义截断前日期时间转换到的时区。实际上,给定的日期时间具有不同的表示形式,具体取决于使用的时区。此参数必须是 datetime.tzinfo 对象。如果是 None ,Django使用 current time zone . 当 USE_TZFalse .

备注

此函数直接在数据库中执行时区转换。因此,数据库必须能够解释 tzinfo.tzname(None) . 这转化为以下要求:

none()

none()

呼叫 none() 将创建一个从不返回任何对象的查询集,并且在访问结果时不会执行任何查询。一个 qs.none() 查询集是 EmptyQuerySet

例如:

>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True

all()

all()

返回A copy 电流的 QuerySet (或) QuerySet 子类)。在您可能希望传递模型管理器或 QuerySet 并对结果进行进一步过滤。调用后 all() 在任何一个对象上,你肯定会有一个 QuerySet 一起工作。

当A QuerySetevaluated 它通常缓存其结果。如果数据库中的数据在 QuerySet 已评估,您可以通过调用 all() 在先前评估的 QuerySet .

union()

union(*other_qs, all=False)

使用SQL的 UNION 运算符组合两个或多个结果 QuerySet S.例如:

>>> qs1.union(qs2, qs3)

这个 UNION 默认情况下,运算符仅选择不同的值。若要允许重复值,请使用 all=True 参数。

union()intersection() ,以及 difference() 返回第一个 QuerySet 即使论据是 QuerySet 其他型号的S。传递不同的模型,只要 SELECT 清单都是一样的 QuerySet S(至少是类型,只要类型顺序相同,名字就不重要了)。在这种情况下,必须使用第一个中的列名 QuerySet 在……里面 QuerySet 方法应用于产生的 QuerySet 。例如:

>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")

此外,只有 LIMITOFFSETCOUNT(*)ORDER BY ,并指定列(即切片, count(), exists(), order_by(), and values()/values_list() ),则允许对生成的 QuerySet 。此外,数据库对组合查询中允许的操作进行了限制。例如,大多数数据库不允许 LIMITOFFSET 在组合查询中。

intersection()

intersection(*other_qs)

使用SQL的 INTERSECT 运算符返回两个或多个共享元素 QuerySet S.例如:

>>> qs1.intersection(qs2, qs3)

union() 为了一些限制。

difference()

difference(*other_qs)

使用SQL的 EXCEPT 运算符只保留存在于 QuerySet 但不是在其他地方 QuerySet S。例如:

>>> qs1.difference(qs2, qs3)

union() 为了一些限制。

extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

有时,django查询语法本身不能轻松地表达复杂的 WHERE 条款。对于这些边缘案例,Django提供了 extra() QuerySet 修饰符-用于将特定子句插入由 QuerySet .

用这种方法作为最后的手段

这是一个旧的API,我们打算在将来的某个时候将其弃用。仅当不能使用其他查询集方法表达查询时才使用它。如果您确实需要使用它,请 file a ticket 使用 QuerySet.extra keyword 使用您的用例(请先检查现有票据列表),这样我们可以增强queryset api以允许删除 extra() . 我们不再改进或修复此方法的错误。

例如,这种使用 extra()

>>> qs.extra(
...     select={"val": "select col from sometable where othercol = %s"},
...     select_params=(someparam,),
... )

相当于:

>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

使用的主要好处 RawSQL 是你可以设置的吗 output_field 如果需要的话。主要的缺点是,如果在原始SQL中引用查询集的某个表别名,那么Django可能会更改该别名(例如,在另一个查询中将查询集用作子查询时)。

警告

每次使用时都要非常小心 extra() . 每次使用它时,都应该转义用户可以通过使用 params 为了防止SQL注入攻击。

也不能在SQL字符串中引用占位符。由于周围的引号,此示例容易受到SQL注入的攻击 %s

SELECT col FROM sometable WHERE othercol = '%s'  # unsafe!

你可以阅读更多关于 Django 的 SQL injection protection 作品。

根据定义,这些额外的查找可能无法移植到不同的数据库引擎(因为您显式地编写了SQL代码),并且违反了dry原则,因此如果可能的话,应该避免它们。

指定一个或多个 paramsselectwheretables . 不需要任何参数,但至少应使用其中一个参数。

  • select

    这个 select 参数允许您在 SELECT 条款。它应该是一个字典,将属性名映射到用于计算该属性的SQL子句。

    例子::

    Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
    

    因此,每个 Entry 对象将具有额外的属性, is_recent ,一个布尔值,表示该项是否 pub_date 大于2006年1月1日。

    Django将给定的SQL片段直接插入 SELECT 语句,因此上述示例的结果SQL如下所示:

    SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
    FROM blog_entry;
    

    下一个示例更高级;它执行子查询以给出每个结果 Blog 对象A entry_count 属性,关联的整数计数 Entry 对象::

    Blog.objects.extra(
        select={
            "entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id"
        },
    )
    

    在这种特殊情况下,我们利用的事实是,查询将已经包含 blog_blog 表在其 FROM 条款。

    上述示例的结果SQL为:

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
    FROM blog_blog;
    

    注意,大多数数据库引擎围绕子查询所需的括号在Django中不需要。 select 条款。还要注意,一些数据库后端(如某些MySQL版本)不支持子查询。

    在一些罕见的情况下,您可能希望将参数传递到 extra(select=...) . 为此,请使用 select_params 参数。

    这将起作用,例如:

    Blog.objects.extra(
        select={"a": "%s", "b": "%s"},
        select_params=("one", "two"),
    )
    

    如果需要使用文字 %s 在选择字符串内,使用序列 %%s .

  • where / tables

    可以定义显式SQL WHERE 子句-可能执行非显式连接-通过使用 where . 您可以手动向SQL添加表 FROM 使用子句 tables .

    wheretables 两者都需要一个字符串列表。所有 where 参数是“和”的任何其他搜索条件。

    例子::

    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    

    …将(大致)转换为以下SQL:

    SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
    

    使用时要小心 tables 参数,如果指定的表已在查询中使用。当您通过 tables 参数django假定您希望该表包含额外的时间(如果已经包含)。这就产生了一个问题,因为表名将被赋予一个别名。如果一个表在一个SQL语句中出现多次,则第二次和随后出现的表必须使用别名,以便数据库能够区分它们。如果你指的是你在额外表中添加的额外表 where 参数这将导致错误。

    通常,您只会添加查询中尚未出现的额外表。但是,如果上述情况确实发生,则有一些解决方案。首先,看看是否可以在不包含额外表的情况下通过,并使用查询中已经存在的表。如果不可能的话,把你的 extra() 在查询集构造的前面调用,以便您的表是该表的第一个使用。最后,如果所有其他操作都失败,请查看生成的查询并重写 where 添加以使用提供给额外表的别名。每次以相同的方式构造查询集时,别名都是相同的,因此您可以依赖别名而不更改。

  • order_by

    如果需要使用包含在 extra() 使用 order_by 参数到 extra() 传递一系列字符串。这些字符串应该是模型字段(与正常的一样 order_by() 方法),格式为 table_name.column_name 或在中指定的列的别名 select 参数到 extra() .

    例如::

    q = Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
    q = q.extra(order_by=["-is_recent"])
    

    这将对所有项目进行排序 is_recent 在结果集前面为真 (True 前排序 False 按降序排列)。

    顺便说一句,这表明你可以多次调用 extra() 它将按您的预期运行(每次都添加新的约束)。

  • params

    这个 where 上面描述的参数可以使用标准的python数据库字符串占位符- '%s' 要指示参数,数据库引擎应自动引用。这个 params 参数是要替换的任何额外参数的列表。

    例子::

    Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
    

    总是使用 params 而不是直接将值嵌入 where 因为 params 将确保根据您的特定后端正确引用值。例如,引号将正确转义。

    坏::

    Entry.objects.extra(where=["headline='Lennon'"])
    

    好::

    Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
    

警告

如果您正在对MySQL执行查询,请注意,在混合类型时,MySQL的静默类型强制可能会导致意外的结果。如果查询的是字符串类型的列,但使用的是整数值,那么在执行比较之前,MySQL会将表中所有值的类型强制为整数。例如,如果表中包含值 'abc''def' 然后你查询 WHERE mycolumn=0 ,两行都匹配。为防止出现这种情况,请在查询中使用值之前执行正确的类型转换。

defer()

defer(*fields)

在某些复杂的数据建模情况下,您的模型可能包含许多字段,其中一些可能包含大量数据(例如,文本字段),或者需要昂贵的处理才能将它们转换为Python对象。如果在最初获取数据时不知道是否需要这些特定字段的情况下使用查询集的结果,可以告诉Django不要从数据库中检索它们。

这是通过将不加载的字段的名称传递给 defer() ::

Entry.objects.defer("headline", "body")

具有延迟字段的查询集仍将返回模型实例。如果您访问该字段(一次一个字段,而不是同时访问所有延迟字段),则将从数据库中检索每个延迟字段。

备注

延迟字段不会像这样从异步代码中延迟加载。取而代之的是,您将获得 SynchronousOnlyOperation 例外。如果您正在编写异步代码,则不应尝试访问您 defer()

您可以多次调用到 defer() . 每次调用都会向延迟集添加新字段::

# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")

字段添加到延迟集的顺序并不重要。调用 defer() 对于已延迟的字段名,这是无害的(该字段仍将被延迟)。

可以推迟相关模型中字段的加载(如果相关模型是通过 select_related() )使用标准双下划线符号分隔相关字段:

Blog.objects.select_related().defer("entry__headline", "entry__body")

如果要清除延迟字段集,请通过 None 作为参数 defer() ::

# Load all fields immediately.
my_queryset.defer(None)

模型中的某些字段不会被延迟,即使您请求它们。您不能推迟主密钥的加载。如果您正在使用 select_related() 要检索相关模型,不应延迟从主模型到相关模型的字段的加载,这样做将导致错误。

类似地,调用 defer() (或其对应对象 only() )包括来自聚合的参数(例如,使用 annotate() )没有意义:这样做会引发异常。聚合值将始终被提取到结果查询集中。

备注

这个 defer() 方法(及其类似方法, only() (以下)仅适用于高级用例。当您仔细分析了您的查询并了解时,它们提供了一个优化。 确切地 您需要哪些信息,以及您已经测量到返回您需要的字段和模型的完整字段集之间的差异将是显著的。

Even if you think you are in the advanced use-case situation, only use defer() when you cannot, at queryset load time, determine if you will need the extra fields or not. If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table). If the columns must stay in the one table for some reason, create a model with Meta.managed = False (see the managed attribute documentation) containing just the fields you normally need to load and use that where you might otherwise call defer(). This makes your code more explicit to the reader, is slightly faster and consumes a little less memory in the Python process.

例如,这两个模型都使用相同的基础数据库表:

class CommonlyUsedModel(models.Model):
    f1 = models.CharField(max_length=10)

    class Meta:
        managed = False
        db_table = "app_largetable"


class ManagedModel(models.Model):
    f1 = models.CharField(max_length=10)
    f2 = models.CharField(max_length=10)

    class Meta:
        db_table = "app_largetable"


# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.defer("f2")

如果需要在非托管模型中复制多个字段,最好使用共享字段创建一个抽象模型,然后让非托管和托管模型从抽象模型继承。

备注

调用时 save() 对于具有延迟字段的实例,只保存加载的字段。见 save() 了解更多详细信息。

only()

only(*fields)

这个 only() 方法在本质上与 defer() 。只有传入此方法的字段和 not 已指定为延迟的,则在计算查询集时立即加载。

如果您的模型中几乎所有字段都需要延迟,请使用 only() 指定互补的字段集可能会导致代码更简单。

假设您有一个带字段的模型 nameagebiography . 以下两个查询集在延迟字段方面是相同的:

Person.objects.defer("age", "biography")
Person.objects.only("name")

无论你什么时候调用 only()替换 要立即加载的字段集。该方法的名称是助记键: only 这些字段将立即加载;其余字段将被延迟。因此,连续调用 only() 结果只考虑最后一个字段:

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

自从 defer() 以递增方式操作(将字段添加到延迟列表中),您可以将调用组合到 only()defer() 事情会有逻辑性的表现:

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")

# Final result loads headline immediately.
Entry.objects.defer("body").only("headline", "body")

注释中的所有注意事项 defer() 文件适用于 only() 也。只有在用尽其他选择之后,才能谨慎地使用它。

vbl.使用 only() 并省略使用 select_related() 也是一个错误。另一方面,调用 only() 在没有任何参数的情况下,将返回查询集获取的每个字段(包括注释)。

和以前一样 defer() ,则不能从异步代码访问未加载的字段并期望加载它们。取而代之的是,您将获得 SynchronousOnlyOperation 例外。确保您可能访问的所有字段都在您的 only() 打电话。

备注

调用时 save() 对于具有延迟字段的实例,只保存加载的字段。见 save() 了解更多详细信息。

备注

使用时 defer() 之后 only() 中的字段 defer() 将覆盖 only() 用于在两者中列出的字段。

using()

using(alias)

此方法用于控制 QuerySet 如果您使用多个数据库,将对其进行评估。此方法采用的唯一参数是数据库的别名,如中定义的 DATABASES .

例如:

# queries the database with the 'default' alias.
>>> Entry.objects.all()

# queries the database with the 'backup' alias
>>> Entry.objects.using("backup")

select_for_update()

select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)

返回将在事务结束前锁定行的查询集,生成 SELECT ... FOR UPDATE 支持的数据库上的SQL语句。

例如::

from django.db import transaction

entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
    for entry in entries:
        ...

当对查询集进行计算时 (for entry in entries 在这种情况下,所有匹配的条目都将被锁定,直到事务块结束,这意味着将阻止其他事务更改或获取它们的锁。

通常,如果另一个事务已经在所选的某一行上获取了锁,则查询将阻塞,直到释放锁为止。如果这不是您想要的行为,请致电 select_for_update(nowait=True) . 这将使调用不阻塞。如果另一个事务已获取冲突锁, DatabaseError 将在计算查询集时引发。您还可以使用 select_for_update(skip_locked=True) 相反。这个 nowaitskip_locked 相互排斥并试图调用 select_for_update() 启用这两个选项将导致 ValueError .

默认情况下, select_for_update() 锁定查询所选的所有行。例如,中指定的相关对象行 select_related() 除了查询集模型的行之外,还锁定。如果不需要,请指定要锁定的相关对象 select_for_update(of=(...)) 使用与相同的字段语法 select_related() . 使用价值 'self' 以引用查询集的模型。

锁定父模型 select_for_update(of=(...))

如果要在使用时锁定父模型 multi-table inheritance ,必须指定父链接字段(默认情况下 <parent_model_name>_ptrof 争论。例如::

Restaurant.objects.select_for_update(of=("self", "place_ptr"))

vbl.使用 select_for_update(of=(...)) 具有指定的字段

如果要锁定模型并指定选定的字段,例如使用 values() 中的每个模型中至少选择一个字段。 of 争论。没有选定字段的模型将不会被锁定。

仅在PostgreSQL上,您可以通过 no_key=True 为了获得一个较弱的锁,这仍然允许创建仅引用锁定行的行(例如,通过外键),而锁处于适当的位置。PostgreSQL文档有关于 row-level lock modes .

你不能使用 select_for_update() 关于可为空的关系:

>>> Person.objects.select_related("hometown").select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join

要避免该限制,如果您不关心空对象,则可以排除它们:

>>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>

这个 postgresqloracle ,以及 mysql 数据库后端支持 select_for_update() 。但是,MariaDB仅支持 nowait 参数,MariaDB 10.6+还支持 skip_locked 参数,并且MySQL支持 nowaitskip_locked ,以及 of 争论。这个 no_key 参数仅在PostgreSQL上受支持。

经过 nowait=Trueskip_locked=Trueno_key=Trueofselect_for_update() 使用不支持这些选项的数据库后端(如mysql)会引发 NotSupportedError . 这可以防止代码意外阻塞。

使用计算查询集 select_for_update() 在后端支持自动提交模式 SELECT ... FOR UPDATE 是一个 TransactionManagementError 错误,因为在这种情况下没有锁定行。如果允许,这将促进数据损坏,并且很容易由调用期望在事务外部运行的代码引起。

使用 select_for_update() 不支持的后端 SELECT ... FOR UPDATE (如sqlite)无效。 SELECT ... FOR UPDATE 将不会添加到查询中,并且在以下情况下不会引发错误: select_for_update() 在自动提交模式下使用。

警告

虽然 select_for_update() 通常在自动提交模式下失败,因为 TestCase 自动包装事务中的每个测试,调用 select_for_update() 在一个 TestCase 即使在外面 atomic() 块将(可能是意外)通过而不引发 TransactionManagementError . 正确测试 select_for_update() 你应该使用 TransactionTestCase .

某些表达式可能不受支持

PostgreSQL不支持 select_for_update() 具有 Window 表达。

raw()

raw(raw_query, params=(), translations=None, using=None)

获取原始SQL查询,执行它,并返回 django.db.models.query.RawQuerySet 实例。这个 RawQuerySet 实例可以像普通的 QuerySet 提供对象实例。

执行原始SQL查询 更多信息。

警告

raw() 总是触发一个新的查询,而不考虑以前的筛选。因此,通常应该从 Manager 或来自新鲜 QuerySet 实例。

返回新的运算符 QuerySet 的S

组合的查询集必须使用相同的模型。

AND (&

组合了两个 QuerySet S使用SQL AND 运算符,其方式类似于链接筛选器。

以下内容等效:

Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1).filter(y=2)

SQL等价物:

SELECT ... WHERE x=1 AND y=2

OR (|

组合二 QuerySet 使用SQL OR 操作员。

以下内容等效:

Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q

Model.objects.filter(Q(x=1) | Q(y=2))

SQL等价物:

SELECT ... WHERE x=1 OR y=2

| 不是交换操作,因为可能会生成不同的(尽管等价的)查询。

XOR (^ )

组合了两个 QuerySet S使用SQL XOR 接线员。一个 XOR 表达式匹配由奇数个操作数匹配的行。

以下内容等效:

Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q

Model.objects.filter(Q(x=1) ^ Q(y=2))

SQL等价物:

SELECT ... WHERE x=1 XOR y=2

备注

XOR 在MariaDB和MySQL上受本地支持。在其他数据库上, x ^ y ^ ... ^ z 被转换为等效的:

(x OR y OR ... OR z) AND
1=MOD(
    (CASE WHEN x THEN 1 ELSE 0 END) +
    (CASE WHEN y THEN 1 ELSE 0 END) +
    ...
    (CASE WHEN z THEN 1 ELSE 0 END),
    2
)
Changed in Django 5.0:

在旧版本中,在没有SQL本机支持的数据库上 XOR 操作员, XOR 返回与一个操作数完全匹配的行。前面的行为与MySQL、MariaDB和Python行为不一致。

不返回的方法 QuerySet 的S

以下 QuerySet 方法评估 QuerySet 还一些东西 以外QuerySet .

这些方法不使用缓存(请参见 缓存和 QuerySet 的S )相反,它们每次被调用时都会查询数据库。

因为这些方法计算QuerySet,所以它们阻塞调用,因此不能从异步代码调用它们的主(同步)版本。因此,每个对象都有一个对应的异步版本,其中 a 前缀-例如,而不是 get(…) 你可以的 await aget(…)

除了它们的异步性之外,通常在行为上没有区别,但是在下面每个方法的旁边注明了任何差别。

get()

get(*args, **kwargs)
aget(*args, **kwargs)

Asynchronous versionaget()

返回与给定查找参数匹配的对象,该对象应采用中描述的格式。 Field lookups . 您应该使用保证唯一的查找,例如唯一约束中的主键或字段。例如::

Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))

如果您希望查询集已经返回一行,那么可以使用 get() 不带任何参数返回该行的对象::

Entry.objects.filter(pk=1).get()

如果 get() 找不到任何对象,它会引发一个 Model.DoesNotExist 例外:

Entry.objects.get(id=-999)  # raises Entry.DoesNotExist

如果 get() 如果找到多个对象,则会引发一个 Model.MultipleObjectsReturned 例外:

Entry.objects.get(name="A Duplicated Name")  # raises Entry.MultipleObjectsReturned

这两个异常类都是模型类的属性,并且特定于该模型。如果你想从几个 get() 对于不同的模型,可以使用它们的泛型基类。例如,可以使用 django.core.exceptions.ObjectDoesNotExist 处理 DoesNotExist 多个型号的例外情况:

from django.core.exceptions import ObjectDoesNotExist

try:
    blog = Blog.objects.get(id=1)
    entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
    print("Either the blog or entry doesn't exist.")

create()

create(**kwargs)
acreate(**kwargs)

Asynchronous versionacreate()

一种方便的方法,用于创建一个对象并将其全部保存在一个步骤中。因此:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

和:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

是等价的。

这个 force_insert 参数在其他地方有文档记录,但这意味着总是会创建一个新对象。通常你不需要担心这个。但是,如果模型包含您设置的手动主键值,并且该值已存在于数据库中,则调用 create() 将失败 IntegrityError 因为主键必须是唯一的。如果您使用的是手动主键,请准备好处理异常。

get_or_create()

get_or_create(defaults=None, **kwargs)
aget_or_create(defaults=None, **kwargs)

Asynchronous versionaget_or_create()

一种方便的查找给定对象的方法 kwargs (如果模型具有所有字段的默认值,则可能为空),如有必要,请创建一个字段。

返回的元组 (object, created) 在哪里 object 是检索或创建的对象,并且 created 是一个布尔值,指定是否创建了新对象。

这是为了防止在并行发出请求时创建重复对象,并作为样板代码的快捷方式。例如::

try:
    obj = Person.objects.get(first_name="John", last_name="Lennon")
except Person.DoesNotExist:
    obj = Person(first_name="John", last_name="Lennon", birthday=date(1940, 10, 9))
    obj.save()

在这里,对于并发请求,多次尝试保存 Person 可以使用相同的参数。为了避免这种竞争条件,可以使用 get_or_create() 像这样::

obj, created = Person.objects.get_or_create(
    first_name="John",
    last_name="Lennon",
    defaults={"birthday": date(1940, 10, 9)},
)

传递给的任何关键字参数 get_or_create() - 除了 一个可选的调用 defaults -将用于 get() 调用。如果找到一个对象, get_or_create() 返回该对象的元组,然后 False .

警告

此方法是原子方法,假定数据库强制关键字参数的唯一性(请参见 uniqueunique_together )如果关键字参数中使用的字段没有唯一性约束,则对该方法的并发调用可能会导致插入多个具有相同参数的行。

可以通过链接为检索到的对象指定更复杂的条件 get_or_create() 具有 filter() 并使用 Q objects . 例如,要检索罗伯特或鲍勃马利(如果两者都存在),并创建后者,否则:

from django.db.models import Q

obj, created = Person.objects.filter(
    Q(first_name="Bob") | Q(first_name="Robert"),
).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})

如果找到多个对象, get_or_create() 加薪 MultipleObjectsReturned . 如果对象是 not 发现, get_or_create() 将实例化并保存新对象,返回新对象的元组 True . 将根据以下算法大致创建新对象:

params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()

在英语中,这意味着从任何不包含双下划线(表示非精确查找)的非“默认值”关键字参数开始。然后添加 defaults ,根据需要重写任何键,并将结果用作模型类的关键字参数。如果在 defaults ,评估它们。如上所述,这是对所用算法的简化,但它包含了所有相关的细节。内部实现有比这更多的错误检查,并处理一些额外的边缘条件;如果您感兴趣,请阅读代码。

如果您有一个名为 defaults 并希望在 get_or_create() 使用 'defaults__exact' ,像这样::

Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})

这个 get_or_create() 方法的错误行为与 create() 当您使用手动指定的主键时。如果需要创建一个对象并且该键已经存在于数据库中,则 IntegrityError 将被提升。

最后,简单介绍一下如何使用 get_or_create() 在Django视图中。请确保仅在以下位置使用 POST 请求,除非你有充分的理由不这样做。 GET 请求不应该对数据有任何影响。相反,您可以使用 POST 每当对页面的请求对您的数据产生副作用时。有关详细信息,请参阅 Safe methods 在HTTP规范中。

警告

你可以使用 get_or_create() 通过 ManyToManyField 属性和反向关系。在这种情况下,您将在该关系的上下文中限制查询。如果你不经常使用它,可能会导致一些完整性问题。

以下型号:

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)


class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

您可以使用 get_or_create() 通过书的章节字段,但它仅获取该书的上下文:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

这是因为它试图通过《尤利西斯》这本书获得或创造“第1章”,但它不能做到任何一个:关系不能获取那一章,因为它与那本书无关,但也不能创造它,因为 title 字段应该是唯一的。

update_or_create()

update_or_create(defaults=None, create_defaults=None, **kwargs)
aupdate_or_create(defaults=None, create_defaults=None, **kwargs)

Asynchronous versionaupdate_or_create()

对象更新对象的便捷方法 kwargs ,如有必要,创建一个新的。两者都有 create_defaultsdefaults 是(字段、值)对的词典。两者中的值 create_defaultsdefaults 可以是可拆卸的。 defaults 用于更新对象,同时 create_defaults 用于创建操作。如果 create_defaults 未提供, defaults 将用于创建操作。

返回的元组 (object, created) 在哪里 object 是创建或更新的对象,并且 created 是一个布尔值,指定是否创建了新对象。

这个 update_or_create 方法尝试根据给定的 kwargs . 如果找到匹配项,它将更新 defaults 字典。

这意味着这是一个到样板文件代码的快捷方式。例如::

defaults = {"first_name": "Bob"}
create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
try:
    obj = Person.objects.get(first_name="John", last_name="Lennon")
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {"first_name": "John", "last_name": "Lennon"}
    new_values.update(create_defaults)
    obj = Person(**new_values)
    obj.save()

随着模型中字段数的增加,这种模式变得相当复杂。上面的例子可以用重写 update_or_create() 像这样::

obj, created = Person.objects.update_or_create(
    first_name="John",
    last_name="Lennon",
    defaults={"first_name": "Bob"},
    create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)

有关名称如何传入的详细说明,请参阅 kwargs 都已解决,请参见 get_or_create()

如上所述 get_or_create() ,此方法容易出现竞争条件,如果在数据库级别不强制唯一性,则可能导致同时插入多行。

喜欢 get_or_create()create() ,如果正在使用手动指定的主键,并且需要创建一个对象,但该键已存在于数据库中,则 IntegrityError 提高了。

Changed in Django 5.0:

这个 create_defaults 添加了参数。

bulk_create()

bulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)
abulk_create(objs, batch_size=None, ignore_conflicts=False, update_conflicts=False, update_fields=None, unique_fields=None)

Asynchronous versionabulk_create()

此方法以高效的方式将提供的对象列表插入到数据库中(通常只有一次查询,无论有多少对象),并以列表的形式返回创建的对象,顺序与提供的相同:

>>> objs = Entry.objects.bulk_create(
...     [
...         Entry(headline="This is a test"),
...         Entry(headline="This is only a test"),
...     ]
... )

不过,这有许多警告:

  • 模型的 save() 将不调用方法,并且 pre_savepost_save 不会发送信号。

  • 它不适用于多表继承方案中的子模型。

  • 如果模型的主键是 AutoFieldignore_conflicts 为FALSE,则只能在某些数据库(当前为PostgreSQL、MariaDB和SQLite 3.35+)上检索主键属性。在其他数据库上,它将不会被设置。

  • 它不适用于多对多关系。

  • 它铸造 objs 到一个列表,该列表完全评估 objs 如果是发电机。强制转换允许检查所有对象,以便可以首先插入具有手动设置的主键的任何对象。如果要批量插入对象而不同时评估整个生成器,则可以使用此技术,只要对象没有任何手动设置的主键::

    from itertools import islice
    
    batch_size = 100
    objs = (Entry(headline="Test %s" % i) for i in range(1000))
    while True:
        batch = list(islice(objs, batch_size))
        if not batch:
            break
        Entry.objects.bulk_create(batch, batch_size)
    

这个 batch_size 参数控制在单个查询中创建的对象数。默认值是在一个批处理中创建所有对象,但sqlite除外,其中默认值是每个查询最多使用999个变量。

在支持它的数据库(Oracle除外)上,设置 ignore_conflicts 参数设置为 True 通知数据库忽略插入不符合约束的任何行的失败,例如重复的唯一值。

在支持它的数据库(Oracle除外)上,设置 update_conflicts 参数设置为 True ,通知数据库进行更新 update_fields 行插入因冲突而失败时。在PostgreSQL和SQLite上,除了 update_fields ,一份 unique_fields 必须提供可能发生冲突的信息。

启用 ignore_conflicts 参数禁用在每个模型实例上设置主键(如果数据库通常支持主键)。

Changed in Django 5.0:

在旧版本中,启用 update_conflicts 参数阻止在每个模型实例上设置主键。

警告

在MySQL和MariaDB上,设置 ignore_conflicts 参数到 True 将某些类型的错误(重复键除外)转换为警告。即使是严格的模式。例如:无效值或不可为null的冲突。见 MySQL documentationMariaDB documentation 了解更多详细信息。

bulk_update()

bulk_update(objs, fields, batch_size=None)
abulk_update(objs, fields, batch_size=None)

Asynchronous versionabulk_update()

此方法通常使用一个查询来高效地更新所提供的模型实例上的给定字段,并返回更新的对象数量:

>>> objs = [
...     Entry.objects.create(headline="Entry 1"),
...     Entry.objects.create(headline="Entry 2"),
... ]
>>> objs[0].headline = "This is entry 1"
>>> objs[1].headline = "This is entry 2"
>>> Entry.objects.bulk_update(objs, ["headline"])
2

QuerySet.update() 用于保存更改,因此这比遍历模型列表和调用 save() 但有几点需要注意:

  • 无法更新模型的主键。

  • 每个模型 save() 未调用方法,并且 pre_savepost_save 没有发送信号。

  • 如果更新大量行中的大量列,则生成的SQL可能非常大。通过指定合适的 batch_size .

  • 更新在多表继承祖先上定义的字段将对每个祖先产生额外的查询。

  • 当单个批处理包含重复项时,只有该批处理中的第一个实例将导致更新。

  • 该函数返回的更新对象数可能少于传入的对象数。这可能是因为传入的重复对象在相同的批处理或争用条件下更新,使得对象不再存在于数据库中。

这个 batch_size 参数控制单个查询中保存的对象数。默认情况下,更新一批中的所有对象,除了对查询中使用的变量数量有限制的sqlite和oracle。

count()

count()
acount()

Asynchronous versionacount()

返回一个整数,该整数表示数据库中与 QuerySet .

例子::

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains="Lennon").count()

A count() 调用执行 SELECT COUNT(*) 在幕后,所以你应该经常使用 count() 而不是将所有记录加载到Python对象中并调用 len() 在结果上(除非您无论如何都需要将对象加载到内存中,在这种情况下 len() 会更快)。

请注意,如果需要 QuerySet 并且还从中检索模型实例(例如,通过对其进行迭代),使用它可能更有效 len(queryset) 这不会导致额外的数据库查询 count() 会。

如果查询集已经被完全检索, count() 将使用该长度,而不是执行额外的数据库查询。

in_bulk()

in_bulk(id_list=None, *, field_name='pk')
ain_bulk(id_list=None, *, field_name='pk')

Asynchronous versionain_bulk()

获取字段值的列表 (id_list )和 field_name 对于这些值,返回一个字典,该字典将每个值映射到具有给定字段值的对象实例。不是 django.core.exceptions.ObjectDoesNotExist 异常将永远由 in_bulk ;即,任何 id_list 与任何实例都不匹配的值将被直接忽略。如果 id_list 则返回查询集中的所有对象。 field_name 必须是唯一字段或不同的字段(如果 distinct() )。 field_name 默认为主键。

示例:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
>>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
>>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}

如果你通过 in_bulk() 一个空列表,你会得到一本空字典。

iterator()

iterator(chunk_size=None)
aiterator(chunk_size=None)

Asynchronous versionaiterator()

计算 QuerySet (通过执行查询)并返回迭代器(请参见 PEP 234 )或异步迭代器(请参见 PEP 492 )如果您调用它的异步版本 aiterator

A QuerySet 通常在内部缓存其结果,以便重复求值不会导致额外的查询。相比之下, iterator() 将直接读取结果,而不在 QuerySet 级别(在内部,默认迭代器调用 iterator() 并缓存返回值)。为. QuerySet 它返回大量只需要访问一次的对象,这可以带来更好的性能和显著的内存减少。

注意使用 iterator() 在一 QuerySet 已评估的将强制它重新评估,重复查询。

iterator() 与以前对 prefetch_related() 只要 chunk_size 是被给予的。更大的值将需要更少的查询来完成预取,但代价是更大的内存使用。

Changed in Django 5.0:

支持 aiterator() 使用之前的调用 prefetch_related() 已添加。

在某些数据库上(例如Oracle, SQLite ),SQL中的最大词条数 IN 子句可能会受到限制。因此,应使用低于此限制的值。(尤其是,当跨两个或多个关系进行预取时, chunk_size 应该足够小,以便每个预取关系的预期结果数仍然低于限制。)

只要QuerySet不预取任何相关对象,就不会为 chunk_size 将导致Django使用隐式缺省值2000。

根据数据库后端的不同,查询结果将同时加载,或者使用服务器端光标从数据库中进行流式传输。

使用服务器端光标

甲骨文与 PostgreSQL 使用服务器端游标从数据库流式传输结果,而不将整个结果集加载到内存中。

Oracle数据库驱动程序始终使用服务器端游标。

对于服务器端光标, chunk_size 参数指定要在数据库驱动程序级别缓存的结果数。获取更大的块会减少数据库驱动程序和数据库之间的往返次数,但会牺牲内存。

在PostgreSQL上,只有在 DISABLE_SERVER_SIDE_CURSORS 设置是 False . 读 事务池和服务器端游标 如果您使用的是在事务池模式下配置的连接池。禁用服务器端游标时,行为与不支持服务器端游标的数据库相同。

没有服务器端光标

MySQL不支持流式结果,因此python数据库驱动程序将整个结果集加载到内存中。然后,数据库适配器使用 fetchmany() 方法定义于 PEP 249 .

sqlite可以使用 fetchmany() 但是,由于sqlite不提供连接内查询之间的隔离,因此在写入要循环访问的表时要小心。见 使用时隔离 QuerySet.iterator() 更多信息。

这个 chunk_size 参数控制从数据库驱动程序中检索的批次django的大小。更大的批处理减少了与数据库驱动程序通信的开销,但代价是内存消耗略有增加。

只要QuerySet不预取任何相关对象,就不会为 chunk_size 将导致Django使用隐式缺省值2000,该值派生自 a calculation on the psycopg mailing list

假设有10-20列的行与文本和数字数据混合,2000将获取少于100kb的数据,这似乎是在传输的行数和过早退出循环时丢弃的数据之间的一个很好的折衷。

latest()

latest(*fields)
alatest(*fields)

Asynchronous versionalatest()

基于给定字段返回表中的最新对象。

此示例返回最新的 Entry 在表格上,根据 pub_date 领域:

Entry.objects.latest("pub_date")

您还可以根据几个字段选择最新的。例如,选择 Entry 最早的 expire_date 当两个条目相同时 pub_date ::

Entry.objects.latest("pub_date", "-expire_date")

负面签到 '-expire_date' 排序方法 expire_date 在里面 下降的 秩序。自从 latest() 获取最后一个结果, Entry 最早的 expire_date 被选中。

如果你的模型 Meta 指定 get_latest_by ,您可以省略 earliest()latest() . 中指定的字段 get_latest_by 默认情况下将使用。

喜欢 get()earliest()latest() 提升 DoesNotExist 如果没有具有给定参数的对象。

注意 earliest()latest() 纯粹为了方便和可读性而存在。

earliest()latest() 可以返回日期为空的实例。

由于将排序委托给数据库,因此如果使用不同的数据库,允许空值的字段的结果的排序可能会有所不同。例如,PostgreSQL和MySQL对空值进行排序,就像它们高于非空值一样,而SQLite则相反。

您可能希望筛选出空值::

Entry.objects.filter(pub_date__isnull=False).latest("pub_date")

earliest()

earliest(*fields)
aearliest(*fields)

Asynchronous versionaearliest()

以其他方式工作 latest() 但方向改变了。

first()

first()
afirst()

Asynchronous versionafirst()

返回与查询集匹配的第一个对象,或者 None 如果没有匹配的对象。如果 QuerySet 未定义排序,则按主键自动排序查询集。这可能会影响聚合结果,如中所述 与以下项目交互 order_by() .

例子::

p = Article.objects.order_by("title", "pub_date").first()

注意 first() 是一种方便的方法,下面的代码示例等效于上面的示例:

try:
    p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
    p = None

last()

last()
alast()

Asynchronous versionalast()

作品像 first() ,但返回查询集中的最后一个对象。

aggregate()

aggregate(*args, **kwargs)
aaggregate(*args, **kwargs)

Asynchronous versionaaggregate()

返回计算的聚合值(平均值、和等)的字典 QuerySet . 每个参数 aggregate() 指定将包含在返回的字典中的值。

Django提供的聚合函数在 Aggregation Functions 下面。因为集料也是 query expressions 可以将聚合与其他聚合或值组合以创建复杂聚合。

使用关键字参数指定的聚合将使用关键字作为批注的名称。匿名参数将根据聚合函数的名称和要聚合的模型字段为其生成一个名称。复杂聚合不能使用匿名参数,必须将关键字参数指定为别名。

例如,当您处理博客条目时,您可能想知道贡献了博客条目的作者的数量:

>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry"))
{'entry__count': 16}

通过使用关键字参数指定聚合函数,可以控制返回的聚合值的名称:

>>> Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 16}

有关聚合的深入讨论,请参见 the topic guide on Aggregation .

exists()

exists()
aexists()

Asynchronous versionaexists()

返回 True 如果 QuerySet 包含任何结果,以及 False 如果不是。它试图以最简单和最快的方式执行查询,但是 does 执行与普通查询几乎相同的查询 QuerySet 查询。

exists() 中是否存在任何对象的搜索非常有用。 QuerySet ,特别是在大型 QuerySet

要查找查询集是否包含任何项,请执行以下操作:

if some_queryset.exists():
    print("There is at least one object in some_queryset")

速度比:

if some_queryset:
    print("There is at least one object in some_queryset")

…但不是很大程度上(因此需要一个大型的查询集来提高效率)。

此外,如果 some_queryset 尚未评估,但您知道它将在某个时间点,然后使用 some_queryset.exists() 将比使用 bool(some_queryset) ,它检索结果,然后检查是否返回了任何结果。

contains()

contains(obj)
acontains(obj)

Asynchronous versionacontains()

退货 True 如果 QuerySetobj ,以及 False 如果没有的话。这会尝试以最简单、最快的方式执行查询。

contains() 中检查对象成员身份时非常有用。 QuerySet ,特别是在大型 QuerySet

检查查询集是否包含特定项目::

if some_queryset.contains(obj):
    print("Entry contained in queryset")

这将比以下操作更快,后者需要评估和迭代整个查询集:

if obj in some_queryset:
    print("Entry contained in queryset")

喜欢 exists() ,如果 some_queryset 尚未评估,但您知道它将在某个点上,然后使用 some_queryset.contains(obj) 将进行额外的数据库查询,通常会导致较慢的整体性能。

update()

update(**kwargs)
aupdate(**kwargs)

Asynchronous versionaupdate()

对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已有新值,则可能不等于更新的行数)。

例如,要关闭2010年发布的所有博客条目的评论,您可以执行以下操作:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

(这假设 Entry 模型有字段 pub_datecomments_on

您可以更新多个字段-没有数量限制。例如,在这里我们更新 comments_onheadline 字段:

>>> Entry.objects.filter(pub_date__year=2010).update(
...     comments_on=False, headline="This is old"
... )

这个 update() 方法被立即应用,并且对 QuerySet 它只能更新模型主表中的列,而不能更新相关模型上的列。您不能这样做,例如:

>>> Entry.objects.update(blog__name="foo")  # Won't work!

不过,仍然可以基于相关字段进行筛选:

>>> Entry.objects.filter(blog__id=1).update(comments_on=True)

你不能调用 update() 在一 QuerySet 已经取了一个切片或不能再过滤的。

这个 update() 方法返回受影响的行数:

>>> Entry.objects.filter(id=64).update(comments_on=True)
1

>>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True)
0

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132

如果您只是更新一个记录,而不需要对模型对象做任何事情,那么最有效的方法是调用 update() 而不是将模型对象加载到内存中。例如,不要这样做:

e = Entry.objects.get(id=10)
e.comments_on = False
e.save()

…这样做:

Entry.objects.filter(id=10).update(comments_on=False)

使用 update() 还可以防止在加载对象和调用之间的短时间内,数据库中的某些内容可能发生变化的争用情况。 save() .

最后,要意识到 update() 在SQL级别进行更新,因此不调用任何 save() 方法,它也不会发出 pre_savepost_save 信号(是调用的结果 Model.save() )如果要为具有自定义 save() 方法,循环它们并调用 save() ,像这样:

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
有序查询集

链锁 order_by() 具有 update() 仅在MariaDB和MySQL上受支持,对于不同的数据库则忽略。这对于按照指定的顺序更新唯一字段非常有用。例如::

Entry.objects.order_by("-number").update(number=F("number") + 1)

备注

order_by() 如果子句包含批注、继承的字段或跨越关系的查阅,则将被忽略。

delete()

delete()
adelete()

Asynchronous versionadelete()

对中的所有行执行SQL删除查询 QuerySet 并返回删除的对象数和一个字典,其中包含每个对象类型的删除数。

这个 delete() 立即应用。你不能调用 delete() 在一 QuerySet 已经取了一个切片或不能再过滤的。

例如,要删除特定博客中的所有条目:

>>> b = Blog.objects.get(pk=1)

# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'blog.Entry': 2, 'blog.Entry_authors': 2})

默认情况下,Django的 ForeignKey 模拟SQL约束 ON DELETE CASCADE -换句话说,任何外键指向要删除的对象的对象都将被删除。例如:

>>> blogs = Blog.objects.all()

# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'blog.Blog': 1, 'blog.Entry': 2, 'blog.Entry_authors': 2})

这个级联行为可以通过 on_delete 论据 ForeignKey .

这个 delete() 方法执行批量删除,不调用任何 delete() 模型上的方法。但是,它确实会发出 pre_deletepost_delete 所有已删除对象的信号(包括级联删除)。

Django需要将对象提取到内存中以发送信号并处理级联。但是,如果没有级联和信号,那么Django可能会采用快速路径,删除对象而不提取到内存中。对于较大的删除,这可能会导致内存使用显著减少。执行的查询量也可以减少。

设置为 on_delete DO_NOTHING 不要阻止删除时采用快速路径。

注意,在对象删除中生成的查询是一个可更改的实现细节。

as_manager()

classmethod as_manager()

返回的实例的类方法 Manager 一份 QuerySet 的方法。见 使用创建经理 QuerySet 方法 了解更多详细信息。

请注意,与本节中的其他条目不同,它没有异步变量,因为它不执行查询。

explain()

explain(format=None, **options)
aexplain(format=None, **options)

Asynchronous versionaexplain()

返回 QuerySet 的执行计划,其中详细说明了数据库将如何执行查询,包括将要使用的任何索引或联接。了解这些详细信息可能有助于提高慢速查询的性能。

例如,使用PostgreSQL时:

>>> print(Blog.objects.filter(title="My Blog").explain())
Seq Scan on blog  (cost=0.00..35.50 rows=10 width=12)
  Filter: (title = 'My Blog'::bpchar)

数据库之间的输出差异很大。

explain() 所有内置数据库后端都支持,但Oracle除外,因为实现并不简单。

这个 format 参数更改数据库的默认输出格式(通常是基于文本的)。PostgreSQL支持 'TEXT''JSON''YAML''XML' 格式。MariaDB和MySQL支持 'TEXT' (也称为 'TRADITIONAL''JSON' 格式。MySQL8.0.16+还支持 'TREE' 格式,类似于PostgreSQL 'TEXT' 如果支持,则默认使用。

某些数据库接受可以返回有关查询的更多信息的标志。将这些标志作为关键字参数传递。例如,使用PostgreSQL时:

>>> print(Blog.objects.filter(title="My Blog").explain(verbose=True, analyze=True))
Seq Scan on public.blog  (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
  Output: id, title
  Filter: (blog.title = 'My Blog'::bpchar)
Planning time: 0.064 ms
Execution time: 0.058 ms

在某些数据库上,标志可能会导致执行查询,这可能会对数据库产生不利影响。例如 ANALYZE 如果存在触发器或调用函数(即使对于 SELECT 查询。

Changed in Django Development version:

支持 generic_plan 添加了PostgreSQL 16+上的选项。

Field 查找

字段查找是如何指定SQL的主要部分的 WHERE 条款。它们被指定为 QuerySet 方法 filter()exclude()get() .

有关介绍,请参见 models and database queries documentation .

Django的内置查找如下所示。也可以写 custom lookups 用于模型字段。

当没有提供查找类型时(如 Entry.objects.get(id=14) )查找类型假定为 exact .

exact

精确匹配。如果提供用于比较的值为 None ,它将被解释为SQL NULL (见 isnull 了解更多详细信息)。

实例:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

SQL等价物:

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

MySQL比较

在MySQL中,数据库表的“排序规则”设置决定 exact 比较区分大小写。这是一个数据库设置, not Django设置。可以将MySQL表配置为使用区分大小写的比较,但也涉及一些权衡。有关详细信息,请参阅 collation sectiondatabases 文档。

iexact

不区分大小写的精确匹配。如果提供用于比较的值为 None ,它将被解释为SQL NULL (见 isnull 了解更多详细信息)。

例子::

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

SQL等价物:

SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;

注意,第一个查询将匹配 'Beatles Blog''beatles blog''BeAtLes BLoG' 等。

SQLite用户

当使用sqlite后端和非ascii字符串时,请记住 database note 关于字符串比较。对于非ASCII字符串,sqlite不区分大小写匹配。

contains

区分大小写的安全壳测试。

例子::

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

SQL等价物:

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

注意这将与标题匹配 'Lennon honored today' 但不是 'lennon honored today' .

SQLite用户

sqlite不支持区分大小写 LIKE 声明; contains 行为像 icontains 对于SQLite。见 database note 更多信息。

icontains

不区分大小写的安全壳试验。

例子::

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

SQL等价物:

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

SQLite用户

当使用sqlite后端和非ascii字符串时,请记住 database note 关于字符串比较。

in

在给定的iterable中;通常是列表、元组或查询集。这不是一个常见的用例,但是字符串(作为iterables)是可以接受的。

实例:

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in="abc")

SQL等价物:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');

您还可以使用queryset动态评估值列表,而不是提供文字值列表:

inner_qs = Blog.objects.filter(name__contains="Cheddar")
entries = Entry.objects.filter(blog__in=inner_qs)

此查询集将作为subselect语句进行计算:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

如果你通过 QuerySet 产生于 values()values_list() 作为 __in 查找,您需要确保只提取结果中的一个字段。例如,这将起作用(过滤博客名称)::

inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)

此示例将引发异常,因为内部查询正在尝试提取两个字段值,其中只需要一个字段值::

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)

性能注意事项

请注意使用嵌套查询,并了解数据库服务器的性能特征(如果有疑问,请进行基准测试!).一些数据库后端,尤其是MySQL,不能很好地优化嵌套查询。在这些情况下,提取值列表并将其传递到第二个查询中更为有效。也就是说,执行两个查询而不是一个:

values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))

注意 list() 访问博客 QuerySet 强制执行第一个查询。如果没有它,将执行嵌套查询,因为 QuerySet 是懒惰的 .

gt

大于。

例子::

Entry.objects.filter(id__gt=4)

SQL等价物:

SELECT ... WHERE id > 4;

gte

大于或等于。

lt

小于。

lte

小于或等于。

startswith

区分大小写从开始。

例子::

Entry.objects.filter(headline__startswith="Lennon")

SQL等价物:

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

sqlite不支持区分大小写 LIKE 声明; startswith 行为像 istartswith 对于SQLite。

istartswith

不区分大小写从开始。

例子::

Entry.objects.filter(headline__istartswith="Lennon")

SQL等价物:

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

SQLite用户

当使用sqlite后端和非ascii字符串时,请记住 database note 关于字符串比较。

endswith

区分大小写以结尾。

例子::

Entry.objects.filter(headline__endswith="Lennon")

SQL等价物:

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

SQLite用户

sqlite不支持区分大小写 LIKE 声明; endswith 行为像 iendswith 对于SQLite。参考 database note 更多文档。

iendswith

不区分大小写以结尾。

例子::

Entry.objects.filter(headline__iendswith="Lennon")

SQL等价物:

SELECT ... WHERE headline ILIKE '%Lennon'

SQLite用户

当使用sqlite后端和非ascii字符串时,请记住 database note 关于字符串比较。

range

范围测试(包括)。

例子::

import datetime

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL等价物:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

你可以使用 range 任何你可以使用的地方 BETWEEN 在SQL中-用于日期、数字和偶数字符。

警告

过滤A DateTimeField WITH日期不包括最后一天的项目,因为边界被解释为“给定日期的上午0点”。如果 pub_date 是一个 DateTimeField ,将上述表达式转换为以下SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';

一般来说,日期和日期时间不能混用。

date

对于日期时间字段,将值强制转换为日期。允许链接其他字段查找。获取日期值。

例子::

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

什么时候? USE_TZTrue ,字段在筛选前转换为当前时区。这需要 time zone definitions in the database .

year

对于日期和日期时间字段,精确的年份匹配。允许链接其他字段查找。需要整数年。

例子::

Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)

SQL等价物:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

iso_year

对于日期和日期时间字段,精确的ISO 8601周编号年份匹配。允许链接其他字段查找。需要整数年。

例子::

Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

month

对于日期和日期时间字段,精确的月份匹配。允许链接其他字段查找。取整数1(一月)到12(十二月)。

例子::

Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)

SQL等价物:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

day

对于日期和日期时间字段,精确的日期匹配。允许链接其他字段查找。需要整数天。

例子::

Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)

SQL等价物:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';

(每个数据库引擎的确切SQL语法各不相同。)

注意:这将与当月第三天(如1月3日、7月3日等)的发布日期匹配。

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

week

对于日期和日期时间字段,根据 ISO-8601 也就是说,星期从星期一开始,第一周包含一年的第一个星期四。

例子::

Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

week_day

对于日期和日期时间字段,为“星期几”匹配。允许链接其他字段查找。

采用一个整数值,表示从1(星期日)到7(星期六)的一周中的某一天。

例子::

Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

注意:这将匹配任何记录 pub_date 这发生在星期一(一周的第2天),而不管发生在哪一个月或哪一年。周日的索引是第1天是星期日,第7天是星期六。

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

iso_week_day

对于日期和日期时间字段,精确匹配ISO 8601的星期几。允许链接其他字段查找。

取一个整数值,表示从1(星期一)到7(星期日)的星期几。

例子::

Entry.objects.filter(pub_date__iso_week_day=1)
Entry.objects.filter(pub_date__iso_week_day__gte=1)

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

注意:这将匹配任何记录 pub_date 它发生在星期一(一周的第一天),不管它发生在哪个月或哪一年。星期几被编入索引,第一天是星期一,第七天是星期天。

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

quarter

对于日期和日期时间字段,为“每年的四分之一”匹配。允许链接其他字段查找。取一个介于1和4之间的整数值,表示一年中的某个季度。

检索第二季度(4月1日至6月30日)条目的示例:

Entry.objects.filter(pub_date__quarter=2)

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

time

对于日期时间字段,将值强制转换为时间。允许链接其他字段查找。采取了 datetime.time 价值。

例子::

Entry.objects.filter(pub_date__time=datetime.time(14, 30))
Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17)))

(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。)

什么时候? USE_TZTrue ,字段在筛选前转换为当前时区。这需要 time zone definitions in the database .

hour

对于日期时间和时间字段,精确的小时匹配。允许链接其他字段查找。取0到23之间的整数。

例子::

Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

SQL等价物:

SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

minute

对于日期时间和时间字段,精确的分钟匹配。允许链接其他字段查找。取0到59之间的整数。

例子::

Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)

SQL等价物:

SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

second

对于日期时间和时间字段,精确的第二个匹配。允许链接其他字段查找。取0到59之间的整数。

例子::

Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)

SQL等价物:

SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';

(每个数据库引擎的确切SQL语法各不相同。)

什么时候? USE_TZTrue ,在筛选之前,日期时间字段将转换为当前时区。这就要求 time zone definitions in the database .

isnull

要么采取 TrueFalse ,对应的SQL查询 IS NULLIS NOT NULL ,分别。

例子::

Entry.objects.filter(pub_date__isnull=True)

SQL等价物:

SELECT ... WHERE pub_date IS NULL;

regex

区分大小写的正则表达式匹配。

正则表达式语法是正在使用的数据库后端的语法。对于没有内置正则表达式支持的sqlite,此功能由(python)用户定义的regexp函数提供,因此正则表达式语法是python的 re 模块。

例子::

Entry.objects.get(title__regex=r"^(An?|The) +")

SQL等价物:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

使用原始字符串(例如, r'foo' 而不是 'foo' )对于传入正则表达式,建议使用语法。

iregex

不区分大小写的正则表达式匹配。

例子::

Entry.objects.get(title__iregex=r"^(an?|the) +")

SQL等价物:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

聚合函数

Django在 django.db.models 模块。有关如何使用这些聚合函数的详细信息,请参阅 the topic guide on aggregation . 见 Aggregate 了解如何创建聚合的文档。

警告

SQLite无法在开箱即用的日期/时间字段上处理聚合。这是因为sqlite中没有本机日期/时间字段,Django当前使用文本字段模拟这些功能。尝试在sqlite中的日期/时间字段上使用聚合将引发 NotSupportedError .

空的查询集或组

聚合函数返回 None 与空格一起使用时 QuerySet 或者说是团体。例如, Sum 聚合函数返回 None 而不是 0 如果 QuerySet 不包含条目或对于非空组中的任何空组 QuerySet 。若要改为返回另一个值,请定义 default 争论。 Count 是此行为的一个例外;它返回 0 如果 QuerySet 为空,因为 Count 不支持 default 争论。

所有聚合具有以下共同参数:

expressions

引用模型上的字段的字符串、字段的转换或 query expressions

output_field

表示 model field 返回值的

备注

当组合多个字段类型时,Django只能确定 output_field 如果所有字段的类型相同。否则,您必须提供 output_field 你自己。

filter

可选的 Q object 用于筛选聚合的行。

条件聚合对批注进行筛选 例如用法。

default

一个可选参数,允许在查询集(或分组)不包含任何条目时指定要用作默认值的值。

**extra

可以为聚合生成的SQL提供额外上下文的关键字参数。

Avg

class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[源代码]

返回给定表达式的平均值,除非指定不同的 output_field .

  • 默认别名: <field>__avg

  • 返回类型: float 如果输入为 int ,否则与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

distinct

可选的。如果 distinct=TrueAvg 返回唯一值的平均值。这是SQL等效于 AVG(DISTINCT <field>) 。缺省值为 False

Count

class Count(expression, distinct=False, filter=None, **extra)[源代码]

返回通过提供的表达式关联的对象的数量。 Count('*') 等同于SQL COUNT(*) 表情。

  • 默认别名: <field>__count

  • 返回类型: int

distinct

可选的。如果 distinct=True ,则计数将仅包括唯一实例。这是SQL等效于 COUNT(DISTINCT <field>) 。缺省值为 False

备注

这个 default 参数不受支持。

Max

class Max(expression, output_field=None, filter=None, default=None, **extra)[源代码]

返回给定表达式的最大值。

  • 默认别名: <field>__max

  • 返回类型:与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

Min

class Min(expression, output_field=None, filter=None, default=None, **extra)[源代码]

返回给定表达式的最小值。

  • 默认别名: <field>__min

  • 返回类型:与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

StdDev

class StdDev(expression, output_field=None, sample=False, filter=None, default=None, **extra)[源代码]

返回所提供表达式中数据的标准偏差。

  • 默认别名: <field>__stddev

  • 返回类型: float 如果输入为 int ,否则与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

sample

可选的。默认情况下, StdDev 返回总体标准差。但是,如果 sample=True ,则返回值将是样本标准差。

Sum

class Sum(expression, output_field=None, distinct=False, filter=None, default=None, **extra)[源代码]

计算给定表达式的所有值的和。

  • 默认别名: <field>__sum

  • 返回类型:与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

distinct

可选的。如果 distinct=TrueSum 返回唯一值的总和。这是SQL等效于 SUM(DISTINCT <field>) 。缺省值为 False

Variance

class Variance(expression, output_field=None, sample=False, filter=None, default=None, **extra)[源代码]

返回所提供表达式中数据的方差。

  • 默认别名: <field>__variance

  • 返回类型: float 如果输入为 int ,否则与输入字段相同,或 output_field 如果提供的话。如果查询集或分组为空, default 是返回的。

sample

可选的。默认情况下, Variance 返回总体差异。但是,如果 sample=True ,则返回值将是样本方差。