QuerySet
API 参考¶该文档描述了 QuerySet
API 的细节。它是建立在 模型 和 数据库查询 指南的材料基础上的,因此,在阅读这篇文档之前,你可能需要阅读和理解这些文档。
在整个参考资料中,我们将使用在 数据库查询指南 中提出的 示例博客模型。
QuerySet
被执行¶QuerySet
本身可以被构造,过滤,切片,或者复制赋值等,是无需访问数据库的。只有在你需要从数据库取出数据或者,向数据库存入数据时才需要访问数据库。
你可以用以下方式执行一个 QuerySet
:
迭代。 一个 QuerySet
是可迭代的,当你第一次迭代它时,它就会执行其数据库查询。例如,这将打印数据库中所有条目的标题:
for e in Entry.objects.all():
print(e.headline)
注意:如果你想做的只是确定至少一个结果是否存在,不要使用这个。使用 exists()
会更有效。
Asynchronous iteration. A QuerySet
can also be iterated over using
async for
:
async for e in Entry.objects.all():
results.append(e)
Both synchronous and asynchronous iterators of QuerySets share the same underlying cache.
切片。 正如在 限制 QuerySet 条目数 中所解释的那样,QuerySet
可以使用 Python 的数组切片语法进行切片。切片一个未执行的 QuerySet
通常会返回另一个未执行的 QuerySet
,但如果使用切片语法的 step
参数,Django 会执行数据库查询,并返回一个列表。切片一个已经执行过的 QuerySet
也会返回一个列表。
还要注意的是,即使对一个未执行的 QuerySet
进行切片,返回另一个未执行的 QuerySet
,也不允许进一步修改它(例如,添加更多的过滤器,或修改排序),因为这不能很好地翻译成 SQL,也没有明确的含义。
Pickle 序列化/缓存。 关于 pickling QuerySets 时涉及的细节,请参见下一节。就本节而言,重要的是,结果是从数据库中读取的。
repr()。 当你调用 repr()
时,所在 QuerySet
会被执行。这是为了方便 Python 交互式解释器,所以当你交互式使用 API 时,可以立即看到你的结果。
len()。 当你调用 len()
时,会执行 QuerySet
。正如你所期望的,这将返回结果列表的长度。
注意:如果你只需要确定集合中的记录数(而不需要实际的对象),那么使用 SQL 的 SELECT COUNT(*)
在数据库层面上处理计数会更有效率。Django 提供了一个 count()
方法正是为了这个原因。
list()。 通过调用 list()
强制执行 QuerySet
。例如:
entry_list = list(Entry.objects.all())
bool()。 在布尔语境中测试 QuerySet
,如使用 bool()
、or
、and
或 if
语句,将导致查询被执行。如果至少有一个结果,则 QuerySet
为 True
,否则为 False
。例如:
if Entry.objects.filter(headline="Test"):
print("There is at least one Entry with the headline Test")
注意:如果你只想确定至少一个结果是否存在(而不需要实际的对象),使用 exences()
更高效。
QuerySet
¶如果你 pickle
序列化一个 QuerySet
,这将迫使所有结果在 pickle 序列化之前加载到内存中。Pickle 序列化通常被用作缓存的前奏,当缓存的查询集被重新加载时,你希望结果已经存在并可以使用(从数据库读取可能需要一些时间,这就违背了缓存的目的)。这意味着,当你取消缓存一个 QuerySet
时,它包含的是它被缓存时的结果,而不是当前在数据库中的结果。
If you only want to pickle the necessary information to recreate the
QuerySet
from the database at a later time, pickle the query
attribute
of the QuerySet
. You can then recreate the original QuerySet
(without
any results loaded) using some code like this:
>>> 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 序列化和反序列化该属性的内容。
对 QuerySet.values_list()
的限制
If you recreate QuerySet.values_list()
using the pickled query
attribute, it will be converted to 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'}]>
QuerySet
API¶这里是 QuerySet
的正式声明:
QuerySet
(model=None, query=None, using=None, hints=None)¶通常当你与 QuerySet
交互时,你会通过 链式过滤器 来使用它。为了实现这一目的,大多数 QuerySet
方法都会返回新的查询集。这些方法将在本节后面详细介绍。
The QuerySet
class has the following public attributes you can use for
introspection:
ordered
¶True
如果 QuerySet
是有序的——即有一个 order_by()
子句或模型上的默认排序。否则为 False
。
db
¶如果现在执行这个查询,将使用的数据库。
备注
QuerySet
的 query
参数的存在是为了让专门的查询子类能够重建内部查询状态。该参数的值是该查询状态的不透明表示,不是公共 API 的一部分。
QuerySet
的方法¶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 中描述。多个参数通过底层 SQL 语句中的 AND
连接。
如果你需要执行更复杂的查询(例如,带有 OR
语句的查询),你可以使用 Q 对象
(*args
)。
exclude()
¶exclude
(*args, **kwargs)¶返回一个新的 QuerySet
,其中包含与给定查找参数不匹配的对象。
查询参数(**kwargs
)的格式应在下文 Field lookups 中描述。多个参数通过底层 SQL 语句中的 AND
连接,整个过程用 NOT()
括起来。
这个例子排除了所有 pub_date
晚于 2005-1-3 且 headline
为“Hello”的条目:
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 或 headline
为“Hello”的条目:
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'
请注意,第二个例子的限制性更强。
如果你需要执行更复杂的查询(例如,带有 OR
语句的查询),你可以使用 Q 对象
(*args
)。
annotate()
¶annotate
(*args, **kwargs)¶用所提供的 查询表达式 列表对 QuerySet
中的每个对象进行注解。表达式可以是一个简单的值,也可以是对模型(或任何相关模型)字段的引用,或者是对与 QuerySet
中的对象相关的对象进行计算的聚合表达式(平均数、总和等)。
annotate()
的每个参数都是一个注解,将被添加到返回的 QuerySet
中的每个对象。
Django 提供的聚合函数在下面的 聚合函数 中介绍。
使用关键字参数指定的注解将使用关键字作为注解的别名。匿名参数将根据聚合函数的名称和被聚合的模型字段为其生成一个别名。只有引用单个字段的聚合表达式才能成为匿名参数。其他一切都必须是关键字参数。
For example, if you were manipulating a list of blogs, you may want to determine how many entries have been made in each blog:
>>> 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
The Blog
model doesn't define an entry__count
attribute by itself,
but by using a keyword argument to specify the aggregate function, you can
control the name of the annotation:
>>> 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
关于聚合的深入讨论,见 关于聚合的专题指南。
alias()
¶alias
(*args, **kwargs)¶与 annotate()
相同,但不是注解中的 QuerySet
对象,而是保存表达式,以便以后与其他 QuerySet
方法重复使用。当不需要表达式本身的结果,但用于过滤、排序或作为复杂表达式的一部分时,这很有用。不查找未使用的值可以从数据库中移除多余的工作,这应该会带来更好的性能。
For example, if you want to find blogs with more than 5 entries, but are not interested in the exact number of entries, you could do this:
>>> 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
返回的结果是按照模型 Meta
中的 ordering
选项给出的排序元组排序的。你可以通过使用 order_by
方法在每个 QuerySet
的基础上覆盖这一点。
举例:
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")
如果 Blog
有 ordering = ['name']
,那么第一个查询集将与以下内容相同:
Entry.objects.order_by("blog__name")
你也可以通过在表达式上调用 asc()
或 esc()
,按 查询表达式 排序:
Entry.objects.order_by(Coalesce("summary", "headline").desc())
asc()
和 esc()
有参数(nulls_first
和 nulls_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
将被多次返回到 order_by()
创建的新 QuerySet
中。换句话说,在 QuerySet
上使用 order_by()
可能会返回比你一开始工作更多的项目——这可能既不是预期的,也不是有用的。
因此,在使用多值字段对结果进行排序时要注意。如果 你能确定你要订购的每个项目只有一个订购数据,这种方法应该不会出现问题。如果不是,请确保结果是你所期望的。
没有办法指定排序是否应该区分大小写。关于大小写敏感,Django 会按照数据库后台的正常排序方式来排序。
你可以用 Lower
将一个字段转换为小写,从而实现大小写一致的排序:
Entry.objects.order_by(Lower("headline").desc())
如果你不想在查询中应用任何排序,甚至是默认的排序,可以不使用参数调用 order_by()
。
你可以通过检查 QuerySet.ordered
属性来判断一个查询是否被排序,如果 QuerySet
以任何方式被排序,则该属性为 True
。
每次 order_by()
调用都将清除以前的任何排序。例如,此查询将按 pub_date
而不是 headline
排序:
Entry.objects.order_by("headline").order_by("pub_date")
警告
排序不是一个免费的操作。你添加到排序中的每个字段都会给你的数据库带来成本。你添加的每个外键都会隐式地包含其所有的默认排序。
如果查询没有指定顺序,那么结果将以未指定的顺序从数据库中返回。只有当按一组字段排序时,才能保证特定的排序,这些字段唯一地标识结果中的每个对象。例如,如果 name
字段不是唯一的,那么按它排序就不能保证具有相同名称的对象总是以相同的顺序出现。
reverse
()¶使用 reverse()
方法来反向返回查询集元素的顺序。第二次调用 reverse()
会将顺序恢复到正常方向。
要检索一个查询集中的“最后”五个项目,你可以这样做:
my_queryset.reverse()[:5]
请注意,这与 Python 中从一个序列的末尾切分不太一样。上面的例子会先返回最后一项,然后返回倒数第二项,以此类推。如果我们有一个 Python 序列,看 seq[-5:]
,我们会先看到倒数第五项。Django 不支持这种访问模式(从末尾切分),因为在 SQL 中不可能有效地做到这一点。
另外,请注意,reverse()
一般只应在有定义顺序的 QuerySet
上调用(例如,当对定义了默认顺序的模型进行查询时,或者当使用 order_by()
时)。如果没有为一个给定的 QuerySet
定义这样的排序,对它调用 reverse()
没有实际效果(在调用 reverse()
之前,排序是未定义的,之后也将保持未定义)。
distinct()
¶distinct
(*fields)¶返回一个新的 QuerySet
,在其 SQL 查询中使用 SELECT DISTINCT
。这将消除查询结果中的重复记录。
默认情况下,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()
调用,数据库在确定哪些行是不同的时候,会比较每行中的 每个 字段。对于带有指定字段名的 distinct()
调用,数据库将只比较指定的字段名。
备注
当你指定字段名时,你 必须 在 QuerySet
中提供一个 order_by()
,而且 order_by()
中的字段必须以 distinct()
中的字段开始,顺序相同。
例如,SELECT DISTINCT ON (a)
给出了列 a
中每个值的第一行。如果你不指定顺序,你会得到一些任意的行。
Examples (those after the first will only work on 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
模型定义了一个通过 name
进行 ordering
:
Entry.objects.order_by("blog").distinct("blog")
...这是不可行的,因为查询将按 blog__name
排序,从而与 DISTINCT ON
表达式不匹配。你必须明确地按关系 _id
字段(本例中为 blog_id
)或被引用的字段(blog__pk
)排序,以确保两个表达式匹配。
values()
¶values
(*fields, **expressions)¶返回一个 QuerySet
,当用作可迭代对象时,返回字典,而不是模型实例。
其中每一个字典都代表一个对象,键与模型对象的属性名相对应。
This example compares the dictionaries of values()
with the normal model
objects:
# 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
应该被限制的字段名。如果你指定了字段,每个字典将只包含你指定字段的字段键/值。如果不指定字段,每个字典将包含数据库表中每个字段的键和值。
Example:
>>> 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'}]>
The values()
method also takes optional keyword arguments,
**expressions
, which are passed through to annotate()
:
>>> from django.db.models.functions import Lower
>>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
You can use built-in and custom lookups in ordering. For example:
>>> 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'}]>
An aggregate within a values()
clause is applied before other arguments
within the same values()
clause. If you need to group by another value,
add it to an earlier values()
clause instead. For example:
>>> 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()
并传递字段名时,你可以传递 foo
或 foo_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()
中的说明。
如果在 extra()
调用之后使用 values()
子句,则 extra()
中的 select
参数所定义的任何字段必须明确地包含在 values()
调用中。任何在 values()
调用之后进行的 extra()
调用将忽略其额外选择的字段。
Combining transforms and aggregates requires the use of two annotate()
calls, either explicitly or as keyword arguments to values()
. As above,
if the transform has been registered on the relevant field type the first
annotate()
can be omitted, thus the following examples are equivalent:
>>> 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}]>
当你知道你只需要一小部分可用字段的值,而且你不需要模型实例对象的功能时,它就很有用。只选择你需要使用的字段会更高效。
最后要注意的是,你可以在调用 values()
之后调用 filter()
、order_by()
等,也就是说这两个调用是相同的:
Blog.objects.values().order_by("id")
Blog.objects.order_by("id").values()
制作 Django 的人喜欢把所有影响 SQL 的方法放在前面,后面(可选的)是任何影响输出的方法(比如 values()
),但这并不重要。这是你真正炫耀自己个性的机会。
You can also refer to fields on related models with reverse relations through
OneToOneField
, ForeignKey
and ManyToManyField
attributes:
>>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
警告
因为 ManyToManyField
属性和逆向关系可以有多条相关的记录,包括这些可以对你的结果集的大小产生倍增效应。如果你在你的 values()
查询中包含了多个这样的字段,这一点会特别明显,在这种情况下,所有可能的组合都会被返回。
Special values for JSONField
on SQLite
Due to the way the JSON_EXTRACT
and JSON_TYPE
SQL functions are
implemented on SQLite, and lack of the BOOLEAN
data type,
values()
will return True
, False
, and None
instead of
"true"
, "false"
, and "null"
strings for
JSONField
key transforms.
values_list()
¶values_list
(*fields, flat=False, named=False)¶This is similar to values()
except that instead of returning dictionaries,
it returns tuples when iterated over. Each tuple contains the value from the
respective field or expression passed into the values_list()
call — so the
first item is the first field, etc. For example:
>>> 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'), ...]>
If you only pass in a single field, you can also pass in the flat
parameter. If True
, this will mean the returned results are single values,
rather than 1-tuples. An example should make the difference clearer:
>>> 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
是错误的。
You can pass named=True
to get results as a
namedtuple()
:
>>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
使用命名元组可能会使使用结果更易读,但代价是将结果转化为命名元组时要付出很小的性能代价。
如果你不向 values_list()
传递任何值,它将按照声明的顺序返回模型中的所有字段。
A common need is to get a specific field value of a certain model instance. To
achieve that, use values_list()
followed by a get()
call:
>>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
values()
和 values_list()
都是针对特定用例的优化:检索数据的子集,而不需要创建一个模型实例的开销。当处理多对多和其他多值关系(如反向外键的一对多关系)时,这个隐喻就失效了,因为“一行一对象”的假设不成立。
For example, notice the behavior when querying across a
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
。
Similarly, when querying a reverse foreign key, None
appears for entries
not having any author:
>>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
Special values for JSONField
on SQLite
Due to the way the JSON_EXTRACT
and JSON_TYPE
SQL functions are
implemented on SQLite, and lack of the BOOLEAN
data type,
values_list()
will return True
, False
, and None
instead of
"true"
, "false"
, and "null"
strings for
JSONField
key transforms.
dates()
¶dates
(field, kind, order='ASC')¶返回一个 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)¶返回一个 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_TZ
为 False
时,它没有效果。
备注
这个函数直接在数据库中执行时区转换。因此,你的数据库必须能够解释 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
()¶返回当前 QuerySet
(或 QuerySet
子类)的 副本。 这在以下情况下很有用:你可能想传入一个模型管理器或一个 QuerySet
,并对结果做进一步过滤。在任何一个对象上调用 all()
后,你肯定会有一个 QuerySet
可以使用。
当一个 QuerySet
被 执行 时,它通常会缓存其结果。如果数据库中的数据可能在 QuerySet
被评估后发生了变化,你可以通过调用 all()
对以前执行过的 QuerySet
进行更新。
union()
¶union
(*other_qs, all=False)¶使用 SQL 的 UNION
操作符来组合两个或多个 QuerySet
的结果。例如:
>>> qs1.union(qs2, qs3)
UNION
操作符默认只选择不同的值。要允许重复的值,使用 all=True
参数。
union()
, intersection()
, and difference()
return model instances
of the type of the first QuerySet
even if the arguments are QuerySet
s
of other models. Passing different models works as long as the SELECT
list
is the same in all QuerySet
s (at least the types, the names don't matter
as long as the types are in the same order). In such cases, you must use the
column names from the first QuerySet
in QuerySet
methods applied to the
resulting QuerySet
. For example:
>>> qs1 = Author.objects.values_list("name")
>>> qs2 = Entry.objects.values_list("headline")
>>> qs1.union(qs2).order_by("name")
此外,只有 LIMIT
、OFFSET
、COUNT(*)
、ORDER BY
和指定列(即切片、count()
、exists()
、order_by()
与 values()
/ values_list()
)允许在结果 QuerySet
中使用。此外,数据库对组合查询中允许的操作也有限制。例如,大多数数据库不允许在组合查询中使用 LIMIT
或 OFFSET
。
intersection()
¶intersection
(*other_qs)¶使用 SQL 的 INTERSECT
操作符来返回两个或多个 QuerySet
的共享元素。例如:
>>> qs1.intersection(qs2, qs3)
一些限制见 union()
。
difference()
¶difference
(*other_qs)¶Uses SQL's EXCEPT
operator to keep only elements present in the
QuerySet
but not in some other QuerySet
s. For example:
>>> 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
生成的 SQL 中。
在万不得已的情况下使用这种方法
这是一个老的 API,我们的目标是在未来的某个时间点废弃。只有当你不能使用其他的查询集方法来表达你的查询时才使用它。如果你确实需要使用它,请使用 QuerySet.extra keyword 并和你的用例(请先检查现有的工单列表)一起 file a ticket ,这样我们就可以增强 QuerySet API 以允许删除 extra()
。我们不再改进或修复该方法的错误。
For example, this use of extra()
:
>>> qs.extra(
... select={"val": "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
is equivalent to:
>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
使用 RawSQL
的主要好处是,如果需要的话,可以设置 output_field
。主要的缺点是,如果你在原始 SQL 中引用了查询集的某个表的别名,那么 Django 有可能会改变这个别名(例如,当查询集在另一个查询中被用作子查询时)。
警告
每当你使用 extra()
时,你应该非常小心。每次使用它时,你应该使用 params
来转义任何用户可以控制的参数,以防止 SQL 注入攻击。
你也不能在 SQL 字符串中引用占位符。这个例子因为在 %s
周围的引号而容易受到 SQL 注入的影响。
SELECT col FROM sometable WHERE othercol = '%s' # unsafe!
你可以阅读更多关于 Django 的 SQL 注入保护 的工作原理。
根据定义,这些额外的查找可能无法移植到不同的数据库引擎中(因为你明确地编写了 SQL 代码),并且违反了 DRY 原则,所以你应该尽可能地避免它们。
指定 params
、select
、where
或 tables
中的一个或多个参数。这些参数都不是必须的,但你应该至少使用其中的一个。
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
对象一个 entry_count
属性,一个相关 Entry
对象的整数:
Blog.objects.extra(
select={
"entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id"
},
)
在这个特殊的情况下,我们利用了这样一个事实,即查询在其 FROM
子句中已经包含 blog_blog
表。
上述例子的 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=...)
中给 SQL 片段传递参数。为此,使用 select_params
参数。
这样做就可以了,比如:
Blog.objects.extra(
select={"a": "%s", "b": "%s"},
select_params=("one", "two"),
)
如果你需要在选择字符串中使用 %s
,请使用序列 %%s
。
where
/tables
你可以通过使用 where
来定义明确的 SQL WHERE
子句——也许是为了执行非明确的连接。你可以通过使用 tables
手动添加表到 SQL FROM
子句中。
where
和 tables
都采用一个字符串列表。所有 where
参数都与任何其他搜索标准“AND”在一起。
举例:
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 会认为你希望额外包含该表,如果已经包含的话。当你通过 tables
参数添加额外的表时,Django 会认为你希望额外地包含该表,如果它已经被包含了。这就会产生一个问题,因为表名会被赋予一个别名。如果一个表在一条 SQL 语句中多次出现,那么第二次和后续的表必须使用别名,这样数据库才能区分它们。如果你指的是你在额外的 where
参数中添加的额外表,这就会造成错误。
一般情况下,你只会添加查询中还没有出现的额外表。但是,如果确实出现了上面概述的情况,有几种解决办法。首先,看看是否可以不包含额外的表,而使用已经在查询中出现的表。如果不可能的话,把你的 extra()
调用放在查询集构造的前面,这样你的表就是那个表的第一次使用。最后,如果所有其他方法都失败了,看一下产生的查询,重写你的 where
加法,使用给你的额外表的别名。每次以同样的方式构造查询集时,别名都会是一样的,所以你可以信赖别名不会改变。
order_by
如果你需要使用你通过 extra()
所包含的一些新字段或表来对结果查询集进行排序,请使用 extra()
的 order_by
参数,并传入一串字符串。这些字符串应该是模型字段(就像在查询集上的普通 order_by()
方法一样),形式为 table_name.column_name
或者是你在 extra()
的 select
参数中指定的列的别名。
例子:
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")
一个有递延字段的查询集仍然会返回模型实例。如果你访问每个递延字段,将从数据库中检索该字段(一次一个,而不是同时访问所有的递延字段)。
备注
Deferred fields will not lazy-load like this from asynchronous code.
Instead, you will get a SynchronousOnlyOperation
exception. If you are
writing asynchronous code, you should not try to access any fields that you
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()
来检索相关的模型,你不应该推迟从主模型连接到相关模型的字段的加载,这样做会导致一个错误。
Similarly, calling defer()
(or its counterpart only()
) including an
argument from an aggregation (e.g. using the result of annotate()
)
doesn't make sense: doing so will raise an exception. The aggregated values
will always be fetched into the resulting queryset.
备注
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")
如果很多字段需要在非托管模型中重复,最好的办法是创建一个共享字段的抽象模型,然后让非托管模型和托管模型从抽象模型中继承。
only()
¶only
(*fields)¶The only()
method is essentially the opposite of defer()
. Only the
fields passed into this method and that are not already specified as deferred
are loaded immediately when the queryset is evaluated.
If you have a model where almost all the fields need to be deferred, using
only()
to specify the complementary set of fields can result in simpler
code.
假设你有一个模型,其字段为 name
、age
和 biography
。就递延字段而言,以下两个查询集是相同的:
Person.objects.defer("age", "biography")
Person.objects.only("name")
每当你调用 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()
。谨慎使用,只有在用尽其他选项后才能使用。
Using only()
and omitting a field requested using select_related()
is
an error as well. On the other hand, invoking only()
without any arguments,
will return every field (including annotations) fetched by the queryset.
As with defer()
, you cannot access the non-loaded fields from asynchronous
code and expect them to load. Instead, you will get a
SynchronousOnlyOperation
exception. Ensure that all fields you might access
are in your only()
call.
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)
来忽略锁定的记录。nowait
和 skip_locked
是相互排斥的,在启用这两个选项的情况下调用 select_for_update()
会导致一个 ValueError
。
默认情况下,select_for_update()
锁定所有被查询选择的行。例如,在 select_related()
中指定的相关对象的行,除了查询集模型的行之外,也会被锁定。如果不希望这样,可以在 select_for_update(of=(...))
中使用与 select_related()
相同的字段语法指定你要锁定的相关对象。使用 'self'
来表示查询集的模型。
在 select_for_update(of=(...))
中锁定父模型
如果在使用 多表继承 时要锁定父模型,必须在 of
参数中指定父链接字段(默认为 <parent_model_name>_ptr
)。例如:
Restaurant.objects.select_for_update(of=("self", "place_ptr"))
在指定的字段使用 select_for_update(of=(...))
如果你想锁定模型并指定选定的字段,例如使用 values()
,你必须从每个模型的 of
参数中至少选择一个字段。没有选定字段的模型将不会被锁定。
仅在 PostgreSQL 上,你可以通过 no_key=True
来获得一个较弱的锁,这仍然允许在锁存在的情况下,创建仅仅引用锁定的行(例如,通过外键)。PostgreSQL 文档中有更多关于 行级锁模式的细节 。
You can't use select_for_update()
on nullable relations:
>>> 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
To avoid that restriction, you can exclude null objects if you don't care about them:
>>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
The postgresql
, oracle
, and mysql
database backends support
select_for_update()
. However, MariaDB only supports the nowait
argument, MariaDB 10.6+ also supports the skip_locked
argument, and MySQL
supports the nowait
, skip_locked
, and of
arguments. The no_key
argument is only supported on PostgreSQL.
在使用不支持这些选项的数据库后端(如 MySQL)向 select_for_update()``传递 ``nowait=True
、skip_locked=True
、no_key=True
或 of
,会产生一个 NotSupportedError
。这可以防止代码意外地阻塞。
在支持 SELECT ... FOR UPDATE
的后端上,用 select_for_update()
在自动提交模式下执行一个查询集是一个 TransactionManagementError
错误,因为在这种情况下行没有被锁定。如果允许这样做,这将促进数据损坏,并且很容易通过调用期望在一个事务之外的事务中运行的代码而引起。
在不支持 SELECT ... FOR UPDATE
的后端(比如 SQLite)使用 select_for_update()
不会有任何影响。SELECT ... FOR UPDATE
不会被添加到查询中,如果 select_for_update()
在自动提交模式下使用,也不会出现错误。
警告
虽然 select_for_update()
通常在自动提交模式下会失败,但由于 TestCase
会自动将每个测试封装在一个事务中,因此在一个 TestCase
中调用 select_for_update()
甚至在 atomic()`()
块外调用 select_for_update()
会(也许会出乎意料地)通过而不会引发 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
的操作符¶组合的查询集必须使用相同的模型。
&
)¶Combines two QuerySet
s using the SQL AND
operator in a manner similar
to chaining filters.
以下的都是相同的:
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
|
)¶使用 SQL OR
操作符将两个 QuerySet
组合起来。
以下的都是相同的:
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
|
不是一个换元运算,因为可能会产生不同的(虽然是等价的)查询。
^
)¶Combines two QuerySet
s using the SQL XOR
operator. A XOR
expression matches rows that are matched by an odd number of operands.
以下的都是相同的:
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
is natively supported on MariaDB and MySQL. On other databases,x ^ y ^ ... ^ z
is converted to an equivalent:(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 )
In older versions, on databases without native support for the SQL
XOR
operator, XOR
returned rows that were matched by exactly
one operand. The previous behavior was not consistent with MySQL,
MariaDB, and Python behavior.
QuerySet
的方法¶以下 QuerySet
方法执行 QuerySet
,并返回 QuerySet
以外的东西。
这些方法不使用缓存(参见 缓存和 QuerySet)。相反,它们每次被调用时都会查询数据库。
Because these methods evaluate the QuerySet, they are blocking calls, and so
their main (synchronous) versions cannot be called from asynchronous code. For
this reason, each has a corresponding asynchronous version with an a
prefix
- for example, rather than get(…)
you can await aget(…)
.
There is usually no difference in behavior apart from their asynchronous nature, but any differences are noted below next to each method.
get()
¶get
(*args, **kwargs)¶aget
(*args, **kwargs)¶Asynchronous version: aget()
返回与给定的查找参数相匹配的对象,其格式应该在 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 version: acreate()
一种方便的方法,用于创建一个对象并一步到位地保存。 因此:
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 version: aget_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
。
警告
假设数据库强制执行关键字参数的唯一性(参见 unique
或 unique_together
),这个方法是原子性的。如果关键字参数中使用的字段没有唯一性约束,那么对该方法的并发调用可能会导致插入具有相同参数的多条记录。
你可以通过将 get_or_create()
和 filter()
串联起来,并使用 Q 对象
为检索对象指定更复杂的条件。例如,如果 Robert 或 Bob Marley 存在,则检索 Robert 或 Bob Marley,否则创建后者:
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
。如果没有找到对象,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
中存在任何可调用对象,则对其进行评估。正如上面所提示的,这是对所使用算法的简化,但它包含了所有相关的细节。内部实现有比这更多的错误检查,并处理一些额外的边缘条件;如果你感兴趣,请阅读代码。
如果你有一个名为 defaults
的字段,并且想在 get_or_create()
中使用它作为精确查询,使用 'defaults__exact'
,像这样:
Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
当你使用手动指定的主键时,get_or_create()
方法的错误行为与 create()
类似。如果需要创建一个对象,而该键已经存在于数据库中,则会引发一个 IntegrityError
。
Finally, a word on using get_or_create()
in Django views. Please make sure
to use it only in POST
requests unless you have a good reason not to.
GET
requests shouldn't have any effect on data. Instead, use POST
whenever a request to a page has a side effect on your data. For more, see
Safe methods in the HTTP spec.
警告
你可以通过 ManyToManyField
属性和反向关系来使用 get_or_create()
。在这种情况下,你将限制在该关系的上下文内进行查询。如果你不持续使用它,这可能会导致一些完整性问题。
如以下模型:
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)
You can use get_or_create()
through Book's chapters field, but it only
fetches inside the context of that book:
>>> 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
出现这种情况是因为它试图通过“Ulysses”这本书获取或创建“Chapter 1”,但它不能做任何事情:关系不能获取该章,因为它与该书无关,但它也不能创建它,因为 title
字段应该是唯一的。
update_or_create()
¶update_or_create
(defaults=None, create_defaults=None, **kwargs)¶aupdate_or_create
(defaults=None, create_defaults=None, **kwargs)¶Asynchronous version: aupdate_or_create()
A convenience method for updating an object with the given kwargs
, creating
a new one if necessary. Both create_defaults
and defaults
are
dictionaries of (field, value) pairs. The values in both create_defaults
and defaults
can be callables. defaults
is used to update the object
while create_defaults
are used for the create operation. If
create_defaults
is not supplied, defaults
will be used for the create
operation.
返回 (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
。
In older versions, update_or_create()
didn't specify update_fields
when calling Model.save()
.
The create_defaults
argument was added.
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 version: abulk_create()
This method inserts the provided list of objects into the database in an efficient manner (generally only 1 query, no matter how many objects there are), and returns created objects as a list, in the same order as provided:
>>> objs = Entry.objects.bulk_create(
... [
... Entry(headline="This is a test"),
... Entry(headline="This is only a test"),
... ]
... )
不过这有一些注意事项:
模型的 save()
方法将不会被调用,pre_save
和 post_save
信号将不会被发送。
在多表继承的情况下,它不能与子模型一起工作。
If the model's primary key is an AutoField
and
ignore_conflicts
is False, the primary key attribute can only be
retrieved on certain databases (currently PostgreSQL, MariaDB 10.5+, and
SQLite 3.35+). On other databases, it will not be set.
对于多对多的关系,它是行不通的。
它将 objs
转换为一个列表,如果 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 个变量。
On databases that support it (all but Oracle), setting the ignore_conflicts
parameter to True
tells the database to ignore failure to insert any rows
that fail constraints such as duplicate unique values.
On databases that support it (all except Oracle), setting the
update_conflicts
parameter to True
, tells the database to update
update_fields
when a row insertion fails on conflicts. On PostgreSQL and
SQLite, in addition to update_fields
, a list of unique_fields
that may
be in conflict must be provided.
Enabling the ignore_conflicts
parameter disables setting the primary key on
each model instance (if the database normally supports it).
In older versions, enabling the update_conflicts
parameter prevented
setting the primary key on each model instance.
警告
在 MySQL 和 MariaDB 上,将 ignore_conflicts
参数设置为 True
将某些类型的错误,除了重复键之外,变成警告。即使在严格模式下也是如此。例如:无效值或不可空值违规。更多细节请参见 MySQL documentation 和 MariaDB documentation 。
bulk_update()
¶bulk_update
(objs, fields, batch_size=None)¶abulk_update
(objs, fields, batch_size=None)¶Asynchronous version: abulk_update()
This method efficiently updates the given fields on the provided model instances, generally with one query, and returns the number of objects updated:
>>> 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_save
和 post_save
信号没有被发送。batch_size
来避免这种情况。batch_size
参数控制一次查询中保存多少对象。默认值是在一个批次中更新所有对象,但 SQLite 和 Oracle 除外,它们对查询中使用的变量数量有限制。
count()
¶count
()¶acount
()¶Asynchronous version: acount()
返回一个整数,表示数据库中与 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()
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 version: ain_bulk()
接收一个字段值的列表(id_list
)和这些值的 field_name
,并返回一个字典,将每个值映射到具有给定字段值的对象实例。in_bulk
不会引发任何 django.core.exceptions.ObjectDoesNotExist
异常;也就是说,任何不匹配任何实例的 id_list
值将被简单地忽略掉。如果没有提供 id_list
,将返回查询集的所有对象。field_name
必须是一个唯一字段或一个独立的字段(如果只有一个字段在 distinct()
中指定)。field_name
默认为主键。
Example:
>>> 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 version: aiterator()
Evaluates the QuerySet
(by performing the query) and returns an iterator
(see PEP 234) over the results, or an asynchronous iterator (see PEP 492)
if you call its asynchronous version aiterator
.
A QuerySet
typically caches its results internally so that repeated
evaluations do not result in additional queries. In contrast, iterator()
will read results directly, without doing any caching at the QuerySet
level
(internally, the default iterator calls iterator()
and caches the return
value). For a QuerySet
which returns a large number of objects that you
only need to access once, this can result in better performance and a
significant reduction in memory.
请注意,在已经被执行的 QuerySet
上使用 iterator()
会迫使它再次执行,重复查询。
iterator()
is compatible with previous calls to prefetch_related()
as
long as chunk_size
is given. Larger values will necessitate fewer queries
to accomplish the prefetching at the cost of greater memory usage.
Support for aiterator()
with previous calls to prefetch_related()
was added.
On some databases (e.g. Oracle, SQLite), the maximum number
of terms in an SQL IN
clause might be limited. Hence values below this
limit should be used. (In particular, when prefetching across two or more
relations, a chunk_size
should be small enough that the anticipated number
of results for each prefetched relation still falls below the limit.)
So long as the QuerySet does not prefetch any related objects, providing no
value for chunk_size
will result in Django using an implicit default of
2000.
根据数据库后端,查询结果将被一次性加载或使用服务器端的游标从数据库中流转。
Oracle 和 PostgreSQL 使用服务器端的游标从数据库流式传输结果,而不需要将整个结果集加载到内存中。
Oracle 数据库驱动程序总是使用服务器端的游标。
对于服务器端的游标,chunk_size
参数指定了要在数据库驱动层缓存的结果数量。获取更大的块数会减少数据库驱动和数据库之间的往返次数,但会牺牲内存。
在 PostgreSQL 上,只有当 DISABLE_SERVER_SIDE_CURSORS
设置为 False
时,才会使用服务器端游标。如果你使用的是配置在事务池模式下的连接池器,请阅读 事务池和服务器端游标。当禁用服务器端游标时,其行为与不支持服务器端游标的数据库相同。
MySQL 不支持流式结果,因此 Python 数据库驱动将整个结果集加载到内存中。然后数据库适配器使用 PEP 249 中定义的 fetchmany()
方法将结果集转化为 Python 行对象。
SQLite 可以使用 fetchmany()
分批获取结果,但由于 SQLite 不提供连接内查询之间的隔离,所以在向被迭代的表写入时要小心。参见 使用 QuerySet.iterator() 时的隔离 了解更多信息。
chunk_size
参数控制 Django 从数据库驱动中获取的批次大小。批量越大,就会减少与数据库驱动通信的开销,但代价是略微增加内存消耗。
So long as the QuerySet does not prefetch any related objects, providing no
value for chunk_size
will result in Django using an implicit default of
2000, a value derived from a calculation on the psycopg mailing list:
假设行数为 10-20 列,文字数据和数字数据混合,2000 要取不到 100KB 的数据,这似乎是一个很好的折中方案,在传输的行数和提前退出循环时丢弃的数据之间。
latest()
¶latest
(*fields)¶alatest
(*fields)¶Asynchronous version: alatest()
根据给定的字段,返回表中最新的对象。
这个例子根据 pub_date
字段返回表中最新的 Entry
:
Entry.objects.latest("pub_date")
你也可以根据几个字段选择最新的。例如,当两个条目具有相同的 pub_date
时,要选择最早的 expire_date
条目:
Entry.objects.latest("pub_date", "-expire_date")
'-expire_date'
中的负号表示按 降 序排列 expire_date
。由于 latest()
得到的是最后一个结果,所以选择了最早的 expire_date
的 Entry
。
如果你模型的 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 version: aearliest()
除了方向改变外,其他工作方式都像 last()
。
first()
¶first
()¶afirst
()¶Asynchronous version: afirst()
返回查询集匹配的第一个对象,如果没有匹配的对象,则返回 None
。如果 QuerySet
没有定义排序,那么查询集自动按主键排序。这可能会影响聚合结果,如 Interaction with 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
aggregate()
¶aggregate
(*args, **kwargs)¶aaggregate
(*args, **kwargs)¶Asynchronous version: aaggregate()
返回对 QuerySet
计算的聚合值(平均值、总和等)的字典。aggregate()
的每个参数都指定了一个将被包含在返回的字典中的值。
Django 提供的聚合函数在下面的 Aggregation Functions 中介绍。由于聚合函数也是 查询表达式,所以你可以将聚合函数与其他聚合函数或值结合起来,创建复杂的聚合函数。
使用关键字参数指定的聚合将使用关键字作为注解的名称。匿名参数将根据聚合函数的名称和被聚合的模型字段为其生成一个名称。复杂的聚合不能使用匿名参数,必须指定一个关键字参数作为别名。
For example, when you are working with blog entries, you may want to know the number of authors that have contributed blog entries:
>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry"))
{'entry__count': 16}
By using a keyword argument to specify the aggregate function, you can control the name of the aggregation value that is returned:
>>> Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 16}
关于聚合的深入讨论,见 关于聚合的专题指南。
exists()
¶exists
()¶aexists
()¶Asynchronous version: aexists()
如果 QuerySet
包含任何结果,则返回 True
,如果不包含,则返回 False
。该函数试图以最简单、最快速的方式执行查询,但它 执行 的查询与普通的 QuerySet
查询几乎相同。
existence()
对于与 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.exences()
比使用 bool(some_queryset)
会做更多的总体工作(一个存在性检查的查询加上一个额外的查询,以便以后检索结果),后者检索结果,然后检查是否有任何返回。
contains()
¶contains
(obj)¶acontains
(obj)¶Asynchronous version: acontains()
如果 QuerySet
包含 obj
,返回 True
,如果不包含 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 version: aupdate()
对指定的字段执行 SQL 更新查询,并返回匹配的行数(如果有些行已经有了新的值,则可能不等于更新的行数)。
For example, to turn comments off for all blog entries published in 2010, you could do this:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
(假定你的 Entry
模型有 pub_date
和 comments_on
。)
You can update multiple fields — there's no limit on how many. For example,
here we update the comments_on
and headline
fields:
>>> Entry.objects.filter(pub_date__year=2010).update(
... comments_on=False, headline="This is old"
... )
The update()
method is applied instantly, and the only restriction on the
QuerySet
that is updated is that it can only update columns in the
model's main table, not on related models. You can't do this, for example:
>>> Entry.objects.update(blog__name="foo") # Won't work!
Filtering based on related fields is still possible, though:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
你不能在一个 QuerySet
上调用 update()
,因为它已经被取走了一个片断或者不能再被过滤。
The update()
method returns the number of affected rows:
>>> 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_save
或 post_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 version: adelete()
对 QuerySet
中的所有行执行 SQL 删除查询,并返回删除的对象数量和每个对象类型的删除数量的字典。
delete()
是即时应用的。你不能对已经被取走一个片断或不能再被过滤的 QuerySet
调用 delete()
。
For example, to delete all the entries in a particular blog:
>>> 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})
By default, Django's ForeignKey
emulates the SQL
constraint ON DELETE CASCADE
— in other words, any objects with foreign
keys pointing at the objects to be deleted will be deleted along with them.
For example:
>>> 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})
这种级联行为通过 ForeignKey
的 on_delete
参数定义。
delete()
方法进行批量删除,并不调用模型上的任何 delete()
方法。但是,它确实为所有被删除的对象(包括级联删除)发出 pre_delete
和 post_delete
信号。
Django 需要将对象获取到内存中来发送信号和处理级联。但是,如果没有级联和信号,那么 Django 可能会采取快速路径删除对象,而不需要将其获取到内存中。对于大面积的删除,这可以使内存使用量大大降低。也可以减少执行查询的数量。
设置为 on_delete
DO_NOTHING
的外键不会阻止在删除时采取快速路径。
需要注意的是,对象删除中产生的查询是一个实现细节,可能会发生变化。
as_manager()
¶as_manager
()¶类方法,该方法返回一个 Manager
的实例,其中包含 QuerySet
的方法的副本。详见 创建带有 QuerySet 方法的管理器 。
Note that unlike the other entries in this section, this does not have an asynchronous variant as it does not execute a query.
explain()
¶explain
(format=None, **options)¶aexplain
(format=None, **options)¶Asynchronous version: aexplain()
返回一个 QuerySet
的执行计划的字符串,它详细说明了数据库将如何执行查询,包括将使用的任何索引或联接。了解这些细节可以帮助你提高慢速查询的性能。
For example, when using 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'
格式。MySQL 8.0.16+ 还支持改进的 'TREE'
格式,它类似于 PostgreSQL 的 'TEXT'
输出,如果支持的话,默认使用。
Some databases accept flags that can return more information about the query. Pass these flags as keyword arguments. For example, when using 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
有些数据库接受的标志可以返回更多 在一些数据库上,标志可能会导致查询被执行,这可能会对你的数据库产生不利影响。 例如,MariaDB、MySQL 8.0.18+ 和 PostgreSQL 支持的 ANALYZE
标志,如果有触发器或调用函数,即使是 SELECT
查询,也可能导致数据的改变。
Field
查找¶字段查找是指定 SQL WHERE
子句的方法。它们被指定为 QuerySet
方法 filter()
、exclude()
和 get()
的关键字参数。
介绍见 模型和数据库查询文档。
Django 的内置查找功能如下。也可以为模型字段写 自定义查找。
为方便起见,当没有提供查找类型时(如 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;
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 中关于字符串比较的内容。SQLite 对非 ASCII 字符串不进行区分大小写的匹配。
contains
¶区分大小写的包含测试。
举例:
Entry.objects.get(headline__contains="Lennon")
SQL 等价于:
SELECT ... WHERE headline LIKE '%Lennon%';
请注意,这将与标题 'Lennon honored today'
相匹配,而不是 'lennon honored today'
。
SQLite 用户
SQLite 不支持区分大小写的 LIKE
语句;contains
的作用就像 SQLite 的 icontains
。更多信息请参见 database note。
icontains
¶不区分大小写的包含测试。
举例:
Entry.objects.get(headline__icontains="Lennon")
SQL 等价于:
SELECT ... WHERE headline ILIKE '%Lennon%';
SQLite 用户
当使用 SQLite 后端和非 ASCII 字符串时,请记住 database note 中关于字符串比较的内容。
in
¶在一个给定的可迭代对象中;通常是一个列表、元组或查询集。这不是一个常见的用例,但字符串(可迭代)是可以接受的。
举例:
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');
你也可以使用一个查询集来动态计算值列表,而不是提供一个字面值列表:
inner_qs = Blog.objects.filter(name__contains="Cheddar")
entries = Entry.objects.filter(blog__in=inner_qs)
该查询集将作为子选择语句执行:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
如果你把一个由 values()
或 values_list()
产生的 QuerySet
作为值传递给 __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))
注意 Blog QuerySet
周围的 list()
调用,以强制执行第一个查询。如果没有它,一个嵌套查询就会被执行,因为 QuerySet 是惰性的。
gte
¶大于等于。
lt
¶小于。
lte
¶小于等于
startswith
¶区分大小写的开头为。
举例:
Entry.objects.filter(headline__startswith="Lennon")
SQL 等价于:
SELECT ... WHERE headline LIKE 'Lennon%';
SQLite 不支持区分大小写的 LIKE
语句;startswith
的作用就像 SQLite 的 istartswith
。
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
的作用类似于 SQLite 的 iendswith
。更多内容请参考 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';
在 SQL 中,你可以在任何你可以使用 BETWEEN
的地方使用 range
——用于日期、数字甚至字符。
警告
用日期过滤 DateTimeField
不会包括最后一天的项目,因为界限被解释为“给定日期的 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 代码片段)。
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 语法因每个数据库引擎而异)。
iso_year
¶对于日期和日期时间字段,精确的 ISO 8601 周号年份匹配。允许链接其他字段的查询。取整数年。
举例:
Entry.objects.filter(pub_date__iso_year=2005)
Entry.objects.filter(pub_date__iso_year__gte=2005)
(确切的 SQL 语法因每个数据库引擎而异)。
month
¶对于日期和日期时间字段,精确的月份匹配。允许链接其他字段的查询。取整数 1(1 月)到 12(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 语法因每个数据库引擎而异)。
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 语法因每个数据库引擎而异)。
请注意,这将匹配任何带有 pub_date 的月份第三天的记录,如 1 月 3 日,7 月 3 日等。
week
¶对于日期和日期时间字段,根据 ISO-8601 ,返回星期号(1-52 或 53),即星期从星期一开始,第一周包含一年的第一个星期四。
举例:
Entry.objects.filter(pub_date__week=52)
Entry.objects.filter(pub_date__week__gte=32, pub_date__week__lte=38)
(由于不同的数据库引擎对相关查询的实现各不相同,因此本次查询不包含等效的 SQL 代码片段)。
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 天是周六。
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
的记录,这些记录都是在星期一(一周的第 1 天)发生的,不管它发生在哪个月或哪个年。周日的索引是第 1 天是星期一,第 7 天是星期天。
quarter
¶对于日期和日期时间字段,“一年的四分之一”匹配。允许链接额外的字段查找。取 1 到 4 之间的整数值,代表一年中的季度。
检索第二季度(4 月 1 日至 6 月 30 日)的条目示例:
Entry.objects.filter(pub_date__quarter=2)
(由于不同的数据库引擎对相关查询的实现各不相同,因此本次查询不包含等效的 SQL 代码片段)。
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 代码片段)。
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 语法因每个数据库引擎而异)。
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 语法因每个数据库引擎而异)。
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 语法因每个数据库引擎而异)。
isnull
¶取 True
或 False
,分别对应 IS NULL
和 IS NOT NULL
的 SQL 查询。
举例:
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
模块中提供了以下聚合函数。关于如何使用这些聚合函数的细节,请参见 关于聚合的主题指南。参见 Aggregate
文档,了解如何创建你的聚合函数。
警告
SQLite 无法处理日期/时间字段的聚合。这是因为 SQLite 中没有原生的日期/时间字段,而 Django 目前使用文本字段来模拟这些功能。试图在 SQLite 中使用日期/时间字段上的聚合将引发 NotSupportedError
。
Empty querysets or groups
Aggregation functions return None
when used with an empty QuerySet
or group. For example, the Sum
aggregation function returns None
instead of 0
if the QuerySet
contains no entries or for any empty
group in a non-empty QuerySet
. To return another value instead, define
the default
argument. Count
is an exception to this behavior; it
returns 0
if the QuerySet
is empty since Count
does not support
the default
argument.
所有聚合体都有以下共同的参数:
output_field
¶一个可选的参数,表示返回值的 模型字段
备注
当组合多个字段类型时,Django 只能在所有字段类型相同的情况下确定 output_field
。否则,你必须自己提供 output_field
。
default
¶一个可选的参数,允许指定一个值作为默认值,当查询集(或分组)不包含条目时使用。
**extra
¶关键字参数,可以为聚合生成的 SQL 提供额外的上下文。
Avg
¶Avg
(expression, output_field=None, distinct=False, filter=None, default=None, **extra)¶返回给定表达式的平均值,除非指定不同的 output_field
,否则必须是数值。
<field>__avg
float
if input is int
, otherwise same as input
field, or output_field
if supplied. If the queryset or grouping is
empty, default
is returned.distinct
¶Optional. If distinct=True
, Avg
returns the mean value of
unique values. This is the SQL equivalent of AVG(DISTINCT <field>)
.
The default value is False
.
Count
¶Count
(expression, distinct=False, filter=None, **extra)¶Returns the number of objects that are related through the provided
expression. Count('*')
is equivalent to the SQL COUNT(*)
expression.
<field>__count
int
distinct
¶Optional. If distinct=True
, the count will only include unique
instances. This is the SQL equivalent of COUNT(DISTINCT <field>)
.
The default value is False
.
备注
不支持 default
参数。
Max
¶Max
(expression, output_field=None, filter=None, default=None, **extra)¶返回给定表达式的最大值。
<field>__max
output_field
if supplied. If the
queryset or grouping is empty, default
is returned.Min
¶Min
(expression, output_field=None, filter=None, default=None, **extra)¶返回给定表达式的最小值。
<field>__min
output_field
if supplied. If the
queryset or grouping is empty, default
is returned.StdDev
¶StdDev
(expression, output_field=None, sample=False, filter=None, default=None, **extra)¶返回给定表达式中数据的标准差。
<field>__stddev
float
if input is int
, otherwise same as input
field, or output_field
if supplied. If the queryset or grouping is
empty, default
is returned.sample
¶Optional. By default, StdDev
returns the population standard
deviation. However, if sample=True
, the return value will be the
sample standard deviation.
Sum
¶Sum
(expression, output_field=None, distinct=False, filter=None, default=None, **extra)¶计算给定表达式的所有值的总和。
<field>__sum
output_field
if supplied. If the
queryset or grouping is empty, default
is returned.distinct
¶Optional. If distinct=True
, Sum
returns the sum of unique
values. This is the SQL equivalent of SUM(DISTINCT <field>)
. The
default value is False
.
Variance
¶Variance
(expression, output_field=None, sample=False, filter=None, default=None, **extra)¶返回给定表达式中数据的方差。
<field>__variance
float
if input is int
, otherwise same as input
field, or output_field
if supplied. If the queryset or grouping is
empty, default
is returned.sample
¶Optional. By default, Variance
returns the population variance.
However, if sample=True
, the return value will be the sample
variance.
12月 05, 2023