---
title: "QuerySet API 参考"
version: 6.0
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/6.0/ref/models/querysets/
canonical: https://djangodocs.dev/zh-hans/6.0/ref/models/querysets/
---
# `QuerySet` API 参考

该文档描述了 `QuerySet` API 的细节。它是建立在 [模型](/zh-hans/6.0/topics/db/models/) 和 [数据库查询](/zh-hans/6.0/topics/db/queries/) 指南的材料基础上的，因此，在阅读这篇文档之前，你可能需要阅读和理解这些文档。

在整个参考资料中，我们将使用在 [数据库查询指南](/zh-hans/6.0/topics/db/queries/) 中提出的  [示例博客模型](/zh-hans/6.0/topics/db/queries/#queryset-model-example)。

## 什么时候 `QuerySet` 被执行

`QuerySet` 本身可以被构造，过滤，切片，或者复制赋值等，是无需访问数据库的。只有在你需要从数据库取出数据或者，向数据库存入数据时才需要访问数据库。

你可以用以下方式执行一个 `QuerySet`：

- **迭代。** 一个 `QuerySet` 是可迭代的，当你第一次迭代它时，它就会执行其数据库查询。例如，这将打印数据库中所有条目的标题：

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

  注意：如果你想做的只是确定至少一个结果是否存在，不要使用这个。使用 [`exists()`](#django.db.models.query.QuerySet.exists) 会更有效。
- **异步迭代**。可以使用 `async for` 来迭代一个 `QuerySet`：

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

  QuerySets 的同步和异步迭代器共享相同的底层缓存。
- **切片。** 正如在 [限制 QuerySet 条目数](/zh-hans/6.0/topics/db/queries/#limiting-querysets) 中所解释的那样，`QuerySet` 可以使用 Python 的数组切片语法进行切片。切片一个未执行的 `QuerySet` 通常会返回另一个未执行的 `QuerySet`，但如果使用切片语法的 `step` 参数，Django 会执行数据库查询，并返回一个列表。切片一个已经执行过的 `QuerySet` 也会返回一个列表。

  还要注意的是，即使对一个未执行的 `QuerySet` 进行切片，返回另一个未执行的 `QuerySet`，也不允许进一步修改它（例如，添加更多的过滤器，或修改排序），因为这不能很好地翻译成 SQL，也没有明确的含义。
- **Pickle 序列化／缓存。** 关于 [pickling QuerySets](#pickling-querysets) 时涉及的细节，请参见下一节。就本节而言，重要的是，结果是从数据库中读取的。
- **repr()。** 当你调用 `repr()` 时，所在 `QuerySet` 会被执行。这是为了方便 Python 交互式解释器，所以当你交互式使用 API 时，可以立即看到你的结果。
- **len()。** 当你调用 `len()` 时，会执行 `QuerySet`。正如你所期望的，这将返回结果列表的长度。

  注意：如果你只需要确定集合中的记录数（而不需要实际的对象），那么使用 SQL 的 `SELECT COUNT(*)` 在数据库层面上处理计数会更有效率。Django 提供了一个 [`count()`](#django.db.models.query.QuerySet.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")
  ```

  注意：如果你只想确定至少一个结果是否存在（而不需要实际的对象），使用 [`exists()`](#django.db.models.query.QuerySet.exists) 更高效。

### Pickle 序列化 `QuerySet`

如果你 [`pickle`](https://docs.python.org/3/library/pickle.html#module-pickle) 序列化一个 `QuerySet`，这将迫使所有结果在 pickle 序列化之前加载到内存中。Pickle 序列化通常被用作缓存的前奏，当缓存的查询集被重新加载时，你希望结果已经存在并可以使用（从数据库读取可能需要一些时间，这就违背了缓存的目的）。这意味着，当你取消缓存一个 `QuerySet` 时，它包含的是它被缓存时的结果，而不是当前在数据库中的结果。

如果你只想要将必要的信息存储为 pickle，在以后的时间从数据库中重新创建 `QuerySet`，可以 pickle `QuerySet` 的 `query` 属性。然后，可以使用类似以下的代码重新创建原始的 `QuerySet` （不加载任何结果）：

```pycon
>>> 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() 的限制**
>
> 如果使用 pickle 重新创建 [`QuerySet.values_list()`](#django.db.models.query.QuerySet.values_list)，它将被转换为 [`QuerySet.values()`](#django.db.models.query.QuerySet.values)：
>
> ```pycon
> >>> 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 of `QuerySet` objects are only valid for the version of Django
> that was used to generate them. If you generate a pickle using Django
> version N, there is no guarantee that pickle will be readable with
> Django version N+1. Pickles should not be used as part of a long-term
> archival strategy.
>
> 由于 pickle 兼容性错误可能很难诊断，比如静默损坏对象，所以当你试图在与序列化 pickle 时不同版本的 Django 中反序列化查询集时，会发出 `RuntimeWarning`。

## `QuerySet` API

这里是 `QuerySet` 的正式声明：

#### `class QuerySet(model=None, query=None, using=None, hints=None)`

通常当你与 `QuerySet` 交互时，你会通过 [链式过滤器](/zh-hans/6.0/topics/db/queries/#chaining-filters) 来使用它。为了实现这一目的，大多数 `QuerySet` 方法都会返回新的查询集。这些方法将在本节后面详细介绍。

`QuerySet` 类具有以下公共属性，可以用于自省：

#### `ordered`

`True` if the `QuerySet` is ordered — i.e. has an
[`order_by()`](#django.db.models.query.QuerySet.order_by) clause or a default ordering on the model.
`False` otherwise.

#### `db`

如果现在执行这个查询，将使用的数据库。

> **Note**
>
> [`QuerySet`](#django.db.models.query.QuerySet) 的 `query` 参数的存在是为了让专门的查询子类能够重建内部查询状态。该参数的值是该查询状态的不透明表示，不是公共 API 的一部分。

### 返回新 `QuerySet` 的方法

Django 提供了一系列的 `QuerySet` 细化方法，这些方法可以修改 `QuerySet` 返回的结果类型或其 SQL 查询的执行方式。

> **Note**
>
> 这些方法不运行数据库查询，因此它们 **可以安全地在异步代码中运行**，而且没有单独的异步版本。

#### `filter()`

#### `filter(*args, **kwargs)`

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

查询参数（`**kwargs`）的格式应在下文 [Field lookups](#id4) 中描述。多个参数通过底层 SQL 语句中的 `AND` 连接。

如果你需要执行更复杂的查询（例如，带有 `OR` 语句的查询），你可以使用 [`Q 对象`](#django.db.models.Q) （`*args`）。

#### `exclude()`

#### `exclude(*args, **kwargs)`

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

查询参数（`**kwargs`）的格式应在下文 [Field lookups](#id4) 中描述。多个参数通过底层 SQL 语句中的 `AND` 连接，整个过程用 `NOT()` 括起来。

这个例子排除了所有 `pub_date` 晚于 2005-1-3 且 `headline` 为“Hello”的条目：

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

用 SQL 术语来说，它的值是：

```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 术语来说，它的值是：

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

请注意，第二个例子的限制性更强。

如果你需要执行更复杂的查询（例如，带有 `OR` 语句的查询），你可以使用 [`Q 对象`](#django.db.models.Q) （`*args`）。

#### `annotate()`

#### `annotate(*args, **kwargs)`

Annotates each object in the `QuerySet` with the provided list of [query
expressions](/zh-hans/6.0/ref/models/expressions/) or [`Q`](#django.db.models.Q) objects.
Each object can be annotated with:

- a simple value,  via `Value()`;
- a reference to a field on the model (or any related models), via `F()`;
- a boolean, via `Q()`; or
- a result from an aggregate expression (averages, sums, etc.) computed over
  the objects that are related to the objects in the `QuerySet`.

`annotate()` 的每个参数都是一个注解，将被添加到返回的 `QuerySet` 中的每个对象。

Django 提供的聚合函数在下面的 [聚合函数](#id6) 中介绍。

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

例如，如果你正在操作一个博客列表，你可能想确定每个博客中有多少条条目：

```pycon
>>> 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` 属性，但通过使用关键字参数来指定聚合函数，你可以控制注释的名称：

```pycon
>>> 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
```

关于聚合的深入讨论，见 [关于聚合的专题指南](/zh-hans/6.0/topics/db/aggregation/)。

#### `alias()`

#### `alias(*args, **kwargs)`

与 [`annotate()`](#django.db.models.query.QuerySet.annotate) 相同，但不是注解中的 `QuerySet` 对象，而是保存表达式，以便以后与其他 `QuerySet` 方法重复使用。当不需要表达式本身的结果，但用于过滤、排序或作为复杂表达式的一部分时，这很有用。不查找未使用的值可以从数据库中移除多余的工作，这应该会带来更好的性能。

例如，如果你想查找具有超过 5 条条目的博客，但不关心具体的条目数量，你可以这样做：

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

`alias()` 可以与 [`annotate()`](#django.db.models.query.QuerySet.annotate)、[`exclude()`](#django.db.models.query.QuerySet.exclude)、[`filter()`](#django.db.models.query.QuerySet.filter)、[`order_by()`](#django.db.models.query.QuerySet.order_by) 和 [`update()`](#django.db.models.query.QuerySet.update) 一起使用。要将别名表达式与其他方法（例如 [`aggregate()`](#django.db.models.query.QuerySet.aggregate)）一起使用，你必须将其提升为注解：

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

[`filter()`](#django.db.models.query.QuerySet.filter) 和 [`order_by()`](#django.db.models.query.QuerySet.order_by) 可以直接接受表达式，但表达式的构建和使用往往不发生在同一个地方（例如，`QuerySet` 方法创建表达式，以便以后在视图中使用）。`alias()` 允许逐步建立复杂的表达式，可能跨越多个方法和模块，用它们的别名指代表达式部分，只用 [`annotate()`](#django.db.models.query.QuerySet.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`](/zh-hans/6.0/ref/models/options/#django.db.models.Options.ordering)，则通过相关模型的主键进行排序。例如，由于 `Blog` 模型没有指定默认排序：

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

...等同于：

```
Entry.objects.order_by("blog__id")
```

如果 `Blog` 有 `ordering = ['name']`，那么第一个查询集将与以下内容相同：

```
Entry.objects.order_by("blog__name")
```

你也可以通过在表达式上调用 [`asc()`](/zh-hans/6.0/ref/models/expressions/#django.db.models.Expression.asc) 或 `esc()`，按 [查询表达式](/zh-hans/6.0/ref/models/expressions/) 排序：

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

[`asc()`](/zh-hans/6.0/ref/models/expressions/#django.db.models.Expression.asc) 和 `esc()` 有参数（`nulls_first` 和 `nulls_last`）来控制如何对空值进行排序。

Be cautious when ordering by fields in related models if you are also using
[`distinct()`](#django.db.models.query.QuerySet.distinct). See the note in [`distinct()`](#django.db.models.query.QuerySet.distinct) for an explanation of how
related model ordering can change the expected results.

> **Note**
>
> 允许指定一个多值字段来对结果进行排序（例如，一个 [`ManyToManyField`](/zh-hans/6.0/ref/models/fields/#django.db.models.ManyToManyField) 字段，或者一个 [`ForeignKey`](/zh-hans/6.0/ref/models/fields/#django.db.models.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())
```

If you don't want any ordering to be applied to a query, not even the default
ordering, call [`order_by()`](#django.db.models.query.QuerySet.order_by) with no parameters.

你可以通过检查 [`QuerySet.ordered`](#django.db.models.query.QuerySet.ordered) 属性来判断一个查询是否被排序，如果 `QuerySet` 以任何方式被排序，则该属性为 `True`。

每次 `order_by()` 调用都将清除以前的任何排序。例如，此查询将按 `pub_date` 而不是 `headline` 排序：

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

> **Warning**
>
> 排序不是一个免费的操作。你添加到排序中的每个字段都会给你的数据库带来成本。你添加的每个外键都会隐式地包含其所有的默认排序。
>
> 如果查询没有指定顺序，那么结果将以未指定的顺序从数据库中返回。只有当按一组字段排序时，才能保证特定的排序，这些字段唯一地标识结果中的每个对象。例如，如果 `name` 字段不是唯一的，那么按它排序就不能保证具有相同名称的对象总是以相同的顺序出现。

#### reverse()

#### `reverse()`

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

要检索一个查询集中的“最后”五个项目，你可以这样做：

```
my_queryset.reverse()[:5]
```

请注意，这与 Python 中从一个序列的末尾切分不太一样。上面的例子会先返回最后一项，然后返回倒数第二项，以此类推。如果我们有一个 Python 序列，看 `seq[-5:]`，我们会先看到倒数第五项。Django 不支持这种访问模式（从末尾切分），因为在 SQL 中不可能有效地做到这一点。

Also, note that `reverse()` should generally only be called on a `QuerySet`
which has a defined ordering (e.g., when querying against a model which defines
a default ordering, or when using [`order_by()`](#django.db.models.query.QuerySet.order_by)). If no such ordering is
defined for a given `QuerySet`, calling `reverse()` on it has no real
effect (the ordering was undefined prior to calling `reverse()`, and will
remain undefined afterward).

#### `distinct()`

#### `distinct(*fields)`

返回一个新的 `QuerySet`，在其 SQL 查询中使用 `SELECT DISTINCT`。这将消除查询结果中的重复记录。

默认情况下，`QuerySet` 不会消除重复的记录。在实践中，这很少是一个问题，因为简单的查询，如 `Blog.objects.all()` 不会引入重复结果行的可能性。但是，如果你的查询跨越了多个表，当 `QuerySet` 被执行时，就有可能得到重复的结果。这时就应该使用 `distinct()`。

> **Note**
>
> [`order_by()`](#django.db.models.query.QuerySet.order_by) 调用中使用的任何字段都包含在 SQL `SELECT` 列中。当与 `distinct()` 结合使用时，这有时会导致意外的结果。如果按相关模型中的字段排序，这些字段将被添加到选定的列中，它们可能会使原本重复的行看起来是不同的。由于额外的列不会出现在返回的结果中（它们只是为了支持排序），所以有时看起来像是返回了非去重的结果。
>
> Similarly, if you use a [`values()`](#django.db.models.query.QuerySet.values) query to restrict the columns
> selected, the columns used in any [`order_by()`](#django.db.models.query.QuerySet.order_by) (or default model
> ordering) will still be involved and may affect uniqueness of the results.
>
> The moral here is that if you are using `distinct()` be careful about
> ordering by related models. Similarly, when using `distinct()` and
> [`values()`](#django.db.models.query.QuerySet.values) together, be careful when ordering by fields not in the
> [`values()`](#django.db.models.query.QuerySet.values) call.

仅在 PostgreSQL 上，你可以传递位置参数（`*fields`），以指定 `DISTINCT` 应适用的字段名称。这相当于一个 `SELECT DISTINCT ON` 的 SQL 查询。这其中的区别是，对于普通的 `distinct()` 调用，数据库在确定哪些行是不同的时候，会比较每行中的 *每个* 字段。对于带有指定字段名的 `distinct()` 调用，数据库将只比较指定的字段名。

> **Note**
>
> 当你指定字段名时，你 *必须* 在 `QuerySet` 中提供一个 `order_by()`，而且 `order_by()` 中的字段必须以 `distinct()` 中的字段开始，顺序相同。
>
> 例如，`SELECT DISTINCT ON (a)` 给出了列 `a` 中每个值的第一行。如果你不指定顺序，你会得到一些任意的行。

示例（在第一个示例之后，只能在 PostgreSQL 上运行）：

```pycon
>>> Author.objects.distinct()
<QuerySet [...]>
>>> Entry.objects.order_by("pub_date").distinct("pub_date")
<QuerySet [...]>
>>> Entry.objects.order_by("blog").distinct("blog")
<QuerySet [...]>
>>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
<QuerySet [...]>
>>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
<QuerySet [...]>
>>> Entry.objects.order_by("author", "pub_date").distinct("author")
<QuerySet [...]>
```

> **Note**
>
> 请记住 [`order_by()`](#django.db.models.query.QuerySet.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`，当用作可迭代对象时，返回字典，而不是模型实例。

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

这个示例比较了 `values()` 的字典与普通的模型对象：

```pycon
# 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` 应该被限制的字段名。如果你指定了字段，每个字典将只包含你指定字段的字段键／值。如果不指定字段，每个字典将包含数据库表中每个字段的键和值。

例如：

```pycon
>>> 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()`](#django.db.models.query.QuerySet.annotate)：

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

你可以在排序中使用内置和 [自定义查找](/zh-hans/6.0/howto/custom-lookups/)。例如：

```pycon
>>> 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()` 子句中。例如：

```pycon
>>> 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`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey)，默认的 `values()` 调用将返回一个名为 `foo_id` 的字典键，因为这是存储实际值的隐藏模型属性的名称（`foo` 属性指的是相关模型）。当你调用 `values()` 并传递字段名时，你可以传递 `foo` 或 `foo_id`，你将得到同样的东西（字典键将与你传递的字段名匹配）。

  例如：

  ```pycon
  >>> 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}, ...]>
  ```
- When using `values()` together with [`distinct()`](#django.db.models.query.QuerySet.distinct), be aware that
  ordering can affect the results. See the note in [`distinct()`](#django.db.models.query.QuerySet.distinct) for
  details.
- If you use a `values()` clause after an [`extra()`](#django.db.models.query.QuerySet.extra) call,
  any fields defined by a `select` argument in the [`extra()`](#django.db.models.query.QuerySet.extra) must
  be explicitly included in the `values()` call. Any [`extra()`](#django.db.models.query.QuerySet.extra) call
  made after a `values()` call will have its extra selected fields
  ignored.
- Calling [`only()`](#django.db.models.query.QuerySet.only) and [`defer()`](#django.db.models.query.QuerySet.defer) after `values()` doesn't make
  sense, so doing so will raise a `TypeError`.
- 组合转换和聚合需要使用两个 [`annotate()`](#django.db.models.query.QuerySet.annotate) 调用，可以显式地使用它们，也可以作为 [`values()`](#django.db.models.query.QuerySet.values) 的关键字参数。与上面一样，如果转换已经在相关字段类型上注册，第一个 [`annotate()`](#django.db.models.query.QuerySet.annotate) 可以省略，因此以下示例是等效的：

  ```pycon
  >>> 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()`），但这并不重要。这是你真正炫耀自己个性的机会。

你还可以通过 `OneToOneField`、`ForeignKey` 和 `ManyToManyField` 属性引用反向关系上的相关模型的字段：

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

> **Warning**
>
> 因为 [`ManyToManyField`](/zh-hans/6.0/ref/models/fields/#django.db.models.ManyToManyField) 属性和逆向关系可以有多条相关的记录，包括这些可以对你的结果集的大小产生倍增效应。如果你在你的 `values()` 查询中包含了多个这样的字段，这一点会特别明显，在这种情况下，所有可能的组合都会被返回。

> **SQLite 的 JSONField 具有一些特殊的值**
>
> 由于 SQLite 上实现了 `JSON_EXTRACT` 和 `JSON_TYPE` SQL 函数的方式以及缺少 `BOOLEAN` 数据类型，`values()` 将为 [`JSONField`](/zh-hans/6.0/ref/models/fields/#django.db.models.JSONField) 键转换返回 `True`、`False` 和 `None`，而不是 `"true"`、`"false"` 和 `"null"` 字符串。

> **Changed in Django 5.2**
>
> The `SELECT` clause generated when using `values()` was updated to
> respect the order of the specified `*fields` and `**expressions`.

#### `values_list()`

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

这与 `values()` 类似，不同之处在于在迭代时，它返回元组而不是字典。每个元组包含传递给 `values_list()` 调用的相应字段或表达式的值 — 因此第一个项是第一个字段，依此类推。例如：

```pycon
>>> 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 元组。一个示例可以更清楚地说明区别：

```pycon
>>> 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()`](https://docs.python.org/3/library/collections.html#collections.namedtuple) 返回：

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

使用命名元组可能会使使用结果更易读，但代价是将结果转化为命名元组时要付出很小的性能代价。

如果你不向 `values_list()` 传递任何值，它将按照声明的顺序返回模型中的所有字段。

一个常见的需求是获取特定模型实例的特定字段值。要实现这一点，使用 `values_list()` 后跟一个 `get()` 调用：

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

`values()` 和 `values_list()` 都是针对特定用例的优化：检索数据的子集，而不需要创建一个模型实例的开销。当处理多对多和其他多值关系（如反向外键的一对多关系）时，这个隐喻就失效了，因为“一行一对象”的假设不成立。

例如，请注意在查询跨越 [`ManyToManyField`](/zh-hans/6.0/ref/models/fields/#django.db.models.ManyToManyField) 时的行为：

```pycon
>>> 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`：

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

> **SQLite 的 JSONField 具有一些特殊的值**
>
> 由于 SQLite 上实现了 `JSON_EXTRACT` 和 `JSON_TYPE` SQL 函数的方式以及缺少 `BOOLEAN` 数据类型，`values_list()` 将为 [`JSONField`](/zh-hans/6.0/ref/models/fields/#django.db.models.JSONField) 键转换返回 `True`、`False` 和 `None`，而不是 `"true"`、`"false"` 和 `"null"` 字符串。

> **Changed in Django 5.2**
>
> The `SELECT` clause generated when using `values_list()` was updated to
> respect the order of the specified `*fields`.

#### `dates()`

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

返回一个 `QuerySet`，它的值是一个 [`datetime.date`](https://docs.python.org/3/library/datetime.html#datetime.date) 对象的列表，代表 `QuerySet` 内容中所有可用的特定日期。

`field` 应该是你的模型的 `DateField` 的名称。`kind` 应该是\`\`"year"`、`"month"`、`"week"\`\` 或 `"day"`。结果列表中的每个 [`datetime.date`](https://docs.python.org/3/library/datetime.html#datetime.date) 对象都被“截断”为给定的\` type\`。

- `"year"` 返回字段的所有不同年份值的列表。
- `"month"` 返回该字段所有不同年／月值的列表。
- `"week"` 返回该字段的所有不同年份／星期值的列表。所有日期都是星期一。
- `"day"` 返回该字段的所有不同年／月／日值的列表。

`order`，默认为 `'ASC'`，应该是 `'ASC'` 或 `'DESC'`。这指定了如何对结果进行排序。

举例：

```pycon
>>> 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`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 对象的列表，代表 `QuerySet` 内容中所有可用的特定日期。

`field_name` 应该是你的模型中 `DateTimeField` 的名称。

`kind` 应该是 `"year"`、`"month"`、`"week"`、`"day"`、`"hour"`、`"minute"` 或 `"second"`。结果列表中的每个 [`datetime.datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 对象都被“截断”为给定的 `type`。

`order`，默认为 `'ASC'`，应该是 `'ASC'` 或 `'DESC'`。这指定了如何对结果进行排序。

`tzinfo` 定义了在截断之前将日期时间转换为的时区。事实上，一个给定的日期时间根据使用的时区有不同的表示方式。这个参数必须是一个 [`datetime.tzinfo`](https://docs.python.org/3/library/datetime.html#datetime.tzinfo) 对象。如果是 `None`，Django 会使用 [current time zone](/zh-hans/6.0/topics/i18n/timezones/#default-current-time-zone)。当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `False` 时，它没有效果。

> **Note**
>
> 这个函数直接在数据库中执行时区转换。因此，你的数据库必须能够解释 `tzinfo.tzname(None)` 的值。这就转化为以下要求：
>
> - SQLite：没有要求。转换是在 Python 中进行的。
> - PostgreSQL：无要求（见 [Time Zones](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES) ）。
> - Oracle：无要求（见 [Choosing a Time Zone File](https://docs.oracle.com/en/database/oracle/oracle-database/18/nlspg/datetime-data-types-and-time-zone-support.html#GUID-805AB986-DE12-4FEA-AF56-5AABCD2132DF) ）。
> - MySQL：用 [mysql\_tzinfo\_to\_sql](https://dev.mysql.com/doc/refman/en/mysql-tzinfo-to-sql.html) 加载时区表。

#### `none()`

#### `none()`

调用 `none()` 将创建一个永远不会返回任何对象的查询集，在访问结果时将不执行任何查询。`qs.none()` 查询集是 `EmptyQuerySet` 的一个实例。

举例：

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

#### `all()`

#### `all()`

Returns a *copy* of the current `QuerySet` (or `QuerySet` subclass). This
can be useful in situations where you might want to pass in either a model
manager or a `QuerySet` and do further filtering on the result. After calling
`all()` on either object, you'll definitely have a `QuerySet` to work with.

当一个 `QuerySet` 被 [执行](#when-querysets-are-evaluated) 时，它通常会缓存其结果。如果数据库中的数据可能在 `QuerySet` 被评估后发生了变化，你可以通过调用 `all()` 对以前执行过的 `QuerySet` 进行更新。

#### `union()`

#### `union(*other_qs, all=False)`

使用 SQL 的 `UNION` 操作符来组合两个或多个 `QuerySet` 的结果。例如：

```
>>> qs1.union(qs2, qs3)
```

`UNION` 操作符默认只选择不同的值。要允许重复的值，使用 `all=True` 参数。

`union()`, `intersection()`, 和 `difference()` 返回第一个 `QuerySet` 类型的模型实例，即使参数是其他模型的 `QuerySet`。只要所有 `QuerySet` 中的 `SELECT` 列表相同（至少类型相同，名称不重要，只要类型的顺序相同），就可以传递不同的模型。在这种情况下，必须在应用于结果 `QuerySet` 的 `QuerySet` 方法中使用来自第一个 `QuerySet` 的列名。例如：

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

In addition, only `LIMIT`, `OFFSET`, `COUNT(*)`, `ORDER BY`, and
specifying columns (i.e. slicing, [`count()`](#django.db.models.query.QuerySet.count), [`exists()`](#django.db.models.query.QuerySet.exists),
[`order_by()`](#django.db.models.query.QuerySet.order_by), and [`values()`](#django.db.models.query.QuerySet.values)/[`values_list()`](#django.db.models.query.QuerySet.values_list)) are allowed
on the resulting `QuerySet`. Further, databases place restrictions on
what operations are allowed in the combined queries. For example, most
databases don't allow `LIMIT` or `OFFSET` in the combined queries.

#### `intersection()`

#### `intersection(*other_qs)`

使用 SQL 的 `INTERSECT` 操作符来返回两个或多个 `QuerySet` 的共享元素。例如：

```pycon
>>> qs1.intersection(qs2, qs3)
```

一些限制见 [`union()`](#django.db.models.query.QuerySet.union)。

#### `difference()`

#### `difference(*other_qs)`

使用 SQL 的 `EXCEPT` 运算符，只保留在一个 `QuerySet` 中存在而在其他某些 `QuerySet` 中不存在的元素。例如：

```pycon
>>> qs1.difference(qs2, qs3)
```

一些限制见 [`union()`](#django.db.models.query.QuerySet.union)。

#### `select_related()`

#### `select_related(*fields)`

返回一个 `QuerySet`，它将“跟随”外键关系，在执行查询时选择额外的相关对象数据。这是一个性能提升器，它导致一个更复杂的单一查询，但意味着以后使用外键关系将不需要数据库查询。

下面的例子说明了普通查找和 `select_related()` 查找之间的区别。下面是标准的查询：

```
# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog
```

这里是 `select_related` 查找：

```
# Hits the database.
e = Entry.objects.select_related("blog").get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog
```

你可以使用 `select_related()` 来处理任何对象的查询集：

```
from django.utils import timezone

# Find all the blogs with entries scheduled to be published in the future.
blogs = set()

for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog"):
    # Without select_related(), this would make a database query for each
    # loop iteration in order to fetch the related blog for each entry.
    blogs.add(e.blog)
```

`filter()` 和 `select_related()` 的顺序并不重要。这些查询集相当于：

```
Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog")
Entry.objects.select_related("blog").filter(pub_date__gt=timezone.now())
```

你可以用类似于查询外键的方式来跟踪外键。如果你有以下模型：

```
from django.db import models

class City(models.Model):
    # ...
    pass

class Person(models.Model):
    # ...
    hometown = models.ForeignKey(
        City,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

class Book(models.Model):
    # ...
    author = models.ForeignKey(Person, on_delete=models.CASCADE)
```

Then a call to `Book.objects.select_related('author__hometown').get(id=4)`
will cache the related `Person` *and* the related `City`:

```
# Hits the database with joins to the author and hometown tables.
b = Book.objects.select_related("author__hometown").get(id=4)
p = b.author  # Doesn't hit the database.
c = p.hometown  # Doesn't hit the database.

# Without select_related()...
b = Book.objects.get(id=4)  # Hits the database.
p = b.author  # Hits the database.
c = p.hometown  # Hits the database.
```

你可以在传递给 `select_related()` 的字段列表中引用任何 [`ForeignKey`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey) 或 [`OneToOneField`](/zh-hans/6.0/ref/models/fields/#django.db.models.OneToOneField) 关系。

你也可以在传递给 `select_related` 的字段列表中引用一个 [`OneToOneField`](/zh-hans/6.0/ref/models/fields/#django.db.models.OneToOneField) 的反方向——也就是说，你可以遍历一个 [`OneToOneField`](/zh-hans/6.0/ref/models/fields/#django.db.models.OneToOneField) 回到定义字段的对象上。不指定字段名，而是使用 [`related_name`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey.related_name) 作为相关对象上的字段。

在某些情况下，你可能希望调用 `select_related()` 来处理很多相关对象，或者你不知道所有的关系。在这些情况下，我们可以调用 `select_related()`，但不使用参数。这将跟随它能找到的所有非空的外键——必须指定可空的外键。在大多数情况下，不建议这样做，因为这可能会使基础查询变得更加复杂，并返回比实际需要的更多数据。

如果需要清除在过去的 `select_related` 调用中添加的相关字段列表，可以将 `None` 作为参数传递：

```pycon
>>> without_relations = queryset.select_related(None)
```

链式调用 `select_related` 的工作方式与其他方法类似，即 `select_related('foo', 'bar')` 等同于 `select_related('foo').select_related('bar')`。

#### `prefetch_related()`

#### `prefetch_related(*lookups)`

返回一个 `QuerySet`，它将在一个批次中自动检索每个指定查询的相关对象。

这与 `select_related` 有类似的目的，二者都是为了阻止因访问相关对象而引起的数据库查询潮，但策略却完全不同。

`select_related` 的工作方式是创建一个 SQL 连接，并在 `SELECT` 语句中包含相关对象的字段。出于这个原因，`select_related` 在同一个数据库查询中得到相关对象。然而，为了避免因跨越“many”关系进行连接而产生更大的结果集，`select_related` 仅限于单值关系——外键和一对一。

另一方面，`prefetch_related` 为每个关系执行单独的查找，并在 Python 中执行“连接”。这使它能够预取许多对多、对一和 [`GenericRelation`](/zh-hans/6.0/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericRelation) 对象，这是使用 `select_related` 无法完成的，除了外键和一对一关系外，它还支持 [`GenericForeignKey`](/zh-hans/6.0/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey) 的预取，但是必须在 [`GenericPrefetch`](/zh-hans/6.0/ref/contrib/contenttypes/#django.contrib.contenttypes.prefetch.GenericPrefetch) 的 `querysets` 参数中提供每个 `ContentType` 的查询集。

例如，假设你有这些模型：

```
from django.db import models

class Topping(models.Model):
    name = models.CharField(max_length=30)

class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def __str__(self):
        return "%s (%s)" % (
            self.name,
            ", ".join(topping.name for topping in self.toppings.all()),
        )
```

并运行：

```pycon
>>> Pizza.objects.all()
<QuerySet [<Pizza: Hawaiian (ham, pineapple)>, <Pizza: Seafood (prawns, smoked salmon)>, ...]>
```

这样做的问题是，每次 `Pizza.__str__()` 要求 `self.toppings.all()` 都要查询数据库，所以 `Pizza.objects.all()` 会在 Toppings 表上对 Pizza `QuerySet` 中的 *每* 项进行查询。

我们可以使用 `prefetch_related` 减少到只有两个查询：

```pycon
>>> Pizza.objects.prefetch_related("toppings")
```

这意味着每一个 `Pizza` 都有一个 `self.toppings.all()`；现在每次调用 `self.toppings.all()` 时，不必再去数据库中寻找这些项目，而是在一次查询中填充的预设 `QuerySet` 缓存中找到它们。

That is, all the relevant toppings will have been fetched in a single query,
and used to make `QuerySet` instances that have a pre-filled cache of the
relevant results; these are then used in the `self.toppings.all()` calls.

`prefetch_related()` 中的附加查询是在 `QuerySet` 开始执行和主要查询被执行后执行的。

请注意，没有机制可以防止另一个数据库查询在主查询和附加查询之间更改项目，这可能会导致不一致的结果。例如，如果在主查询执行后删除了一份 `Pizza`，在附加查询中将不会返回其配料，看起来就像披萨没有配料一样：

```pycon
>>> Pizza.objects.prefetch_related("toppings")
#  "Hawaiian" Pizza was deleted in another shell.
<QuerySet [<Pizza: Hawaiian ()>, <Pizza: Seafood (prawns, smoked salmon)>]>
```

如果你有一个作为模型实例的可迭代对象，你可以使用 [`prefetch_related_objects()`](#django.db.models.prefetch_related_objects) 函数在这些实例上预取相关属性。

Note that the result cache of the primary `QuerySet` and all specified
related objects will then be fully loaded into memory. This changes the typical
behavior of a `QuerySet`, which normally tries to avoid loading all objects
into memory before they are needed, even after a query has been executed in the
database.

> **Note**
>
> Remember that, as always with `QuerySet` objects, any subsequent chained
> methods which imply a different database query will ignore previously
> cached results, and retrieve data using a fresh database query. So, if you
> write the following:
>
> ```pycon
> >>> pizzas = Pizza.objects.prefetch_related("toppings")
> >>> [list(pizza.toppings.filter(spicy=True)) for pizza in pizzas]
> ```
>
> ...那么 `pizza.toppings.all()` 已经被预取的事实对你没有帮助。`prefetch_related('toppings')` 意味着 `pizza.toppings.all()`，但 `pizza.toppings.filter()` 是一个新的、不同的查询。预设缓存在这里帮不上忙，事实上它损害了性能，因为你做了一个你没有使用过的数据库查询。所以要谨慎使用这个功能！
>
> 此外，如果你在 [`related managers`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager) 上调用数据库更改方法 [`add()`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.add)、[`create()`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.create)、[`remove()`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.remove)、[`clear()`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.clear) 或 [`set()`](/zh-hans/6.0/ref/models/relations/#django.db.models.fields.related.RelatedManager.set)，关系的任何预取缓存都将被清除。

你也可以用普通的 join 语法来做相关字段的相关字段。假设我们在上面的例子中多了一个模型：

```
class Restaurant(models.Model):
    pizzas = models.ManyToManyField(Pizza, related_name="restaurants")
    best_pizza = models.ForeignKey(
        Pizza, related_name="championed_by", on_delete=models.CASCADE
    )
```

以下都是合法的：

```pycon
>>> Restaurant.objects.prefetch_related("pizzas__toppings")
```

这将预取所有属于餐馆的披萨，以及所有属于这些披萨的配料。这将导致总共 3 个数据库查询——一个查询餐厅，一个查询披萨，一个查询配料。

```pycon
>>> Restaurant.objects.prefetch_related("best_pizza__toppings")
```

这将为每家餐厅获取最好的比萨饼和最好的比萨饼的所有配料。这将在 3 个数据库查询中完成——一个查询餐厅，一个查询“最佳披萨”，一个查询配料。

`best_pizza` 关系也可以使用 `select_related` 获取，以将查询计数减少到 2：

```pycon
>>> Restaurant.objects.select_related("best_pizza").prefetch_related("best_pizza__toppings")
```

由于预取是在主查询之后执行的（其中包括 `select_related` 所需要的连接），它能够检测到 `best_pizza` 对象已经被取走了，它将跳过再次取走它们。

链式调用 `prefetch_related` 将累积预取的查找。要清除任何 `prefetch_related` 行为，传递 `None` 作为参数：

```pycon
>>> non_prefetched = qs.prefetch_related(None)
```

在使用 `prefetch_related` 时，需要注意的一个区别是，查询创建的对象可以在与其相关的不同对象之间共享，即一个 Python 模型实例可以出现在返回的对象树的多个点上。这通常会发生在外键关系中。通常情况下，这种行为不会有问题，而且事实上会节省内存和 CPU 时间。

虽然 `prefetch_related` 支持预取 `GenericForeignKey` 关系，但查询次数将取决于数据。由于一个 `GenericForeignKey` 可以引用多个表中的数据，所以需要对每个被引用的表进行一次查询，而不是对所有项目进行一次查询。如果还没有获取相关的行，可以对 `ContentType` 表进行额外的查询。

`prefetch_related` 在大多数情况下，将使用使用“IN”操作符的 SQL 查询来实现。这意味着对于一个大的 `QuerySet` 可能会生成一个大的“IN”子句，这取决于数据库，在解析或执行 SQL 查询时可能会有自己的性能问题。一定要针对自己的用例进行剖析！

如果使用 `iterator()` 运行查询，只有在提供了 `chunk_size` 的值时，才会观察到 `prefetch_related()` 调用。

你可以使用 [`Prefetch`](#django.db.models.Prefetch) 对象来进一步控制预取操作。

最简单的形式 `Prefetch` 相当于传统的基于字符串的查找。

```pycon
>>> from django.db.models import Prefetch
>>> Restaurant.objects.prefetch_related(Prefetch("pizzas__toppings"))
```

你可以用可选的 `queryset` 参数提供一个自定义查询集。这可以用来改变查询集的默认排序。

```pycon
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas__toppings", queryset=Toppings.objects.order_by("name"))
... )
```

Or to call [`select_related()`](#django.db.models.query.QuerySet.select_related) when
applicable to reduce the number of queries even further:

```pycon
>>> Pizza.objects.prefetch_related(
...     Prefetch("restaurants", queryset=Restaurant.objects.select_related("best_pizza"))
... )
```

你也可以用可选的 `to_attr` 参数将预取结果分配给一个自定义属性。结果将直接存储在一个列表中。

这允许用不同的 `QuerySet` 预取同一关系多次；例如：

```pycon
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas", to_attr="menu"),
...     Prefetch("pizzas", queryset=vegetarian_pizzas, to_attr="vegetarian_menu"),
... )
```

使用自定义 `to_attr` 创建的查找仍然可以像往常一样被其他查找遍历。

```pycon
>>> vegetarian_pizzas = Pizza.objects.filter(vegetarian=True)
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas", queryset=vegetarian_pizzas, to_attr="vegetarian_menu"),
...     "vegetarian_menu__toppings",
... )
```

在对预取结果进行过滤时，建议使用 `to_attr`，因为它比将过滤后的结果存储在相关管理器的缓存中更不含糊。

```pycon
>>> queryset = Pizza.objects.filter(vegetarian=True)
>>>
>>> # Recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch("pizzas", queryset=queryset, to_attr="vegetarian_pizzas")
... )
>>> vegetarian_pizzas = restaurants[0].vegetarian_pizzas
>>>
>>> # Not recommended:
>>> restaurants = Restaurant.objects.prefetch_related(
...     Prefetch("pizzas", queryset=queryset),
... )
>>> vegetarian_pizzas = restaurants[0].pizzas.all()
```

Custom prefetching also works with single related relations like
forward `ForeignKey` or `OneToOneField`. Generally you'll want to use
[`select_related()`](#django.db.models.query.QuerySet.select_related) for these relations, but there are a number of cases
where prefetching with a custom `QuerySet` is useful:

- 你要使用一个 `QuerySet`，对相关模型进行进一步的预取。
- 你想只预取相关对象的一个子集。
- 你要使用性能优化技术，比如 [`递延字段`](#django.db.models.query.QuerySet.defer)。

  ```pycon
  >>> queryset = Pizza.objects.only("name")
  >>>
  >>> restaurants = Restaurant.objects.prefetch_related(
  ...     Prefetch("best_pizza", queryset=queryset)
  ... )
  ```

在使用多个数据库时，`Prefetch` 将尊重您的数据库选择。如果内部查询没有指定数据库，它将使用外部查询选择的数据库。以下所有方式都是有效的：

```pycon
>>> # Both inner and outer queries will use the 'replica' database
>>> Restaurant.objects.prefetch_related("pizzas__toppings").using("replica")
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas__toppings"),
... ).using("replica")
>>>
>>> # Inner will use the 'replica' database; outer will use 'default' database
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
... )
>>>
>>> # Inner will use 'replica' database; outer will use 'cold-storage' database
>>> Restaurant.objects.prefetch_related(
...     Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
... ).using("cold-storage")
```

> **Note**
>
> 查询的顺序很重要。
>
> 下面举例说明：
>
> ```pycon
> >>> prefetch_related("pizzas__toppings", "pizzas")
> ```
>
> 即使它是无序的，这也是可行的，因为 `'pizzas__toppings'` 已经包含了所有需要的信息，因此第二个参数 `'pizzas'` 实际上是多余的。
>
> ```pycon
> >>> prefetch_related("pizzas__toppings", Prefetch("pizzas", queryset=Pizza.objects.all()))
> ```
>
> 这将引发一个 `ValueError`，因为它试图重新定义一个先前看到的查询的查询集。请注意，一个隐式查询集被创建为遍历 `''pizzas'` 作为 `''pizzas__toppings'` 查询的一部分。
>
> ```pycon
> >>> prefetch_related("pizza_list__toppings", Prefetch("pizzas", to_attr="pizza_list"))
> ```
>
> 这将触发一个 `AttributeError`，因为 `'pizza_list'` 在处理 `'pizza_list__toppings'` 时还不存在。
>
> 这种考虑不限于使用 `Prefetch` 对象。一些高级技术可能要求按照特定的顺序进行查找，以避免产生额外的查询；因此，建议总是仔细地安排 `prefetch_related` 参数的顺序。

#### `extra()`

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

有时候，Django 查询语法本身并不能很容易地表达一个复杂的 `WHERE` 子句。对于这些边缘情况，Django 提供了 `extra()` `QuerySet` 修饰符——用于将特定的子句注入到由 `QuerySet` 生成的 SQL 中。

> **在万不得已的情况下使用这种方法**
>
> This is an old API that we aim to deprecate at some point in the future.
> Use it only if you cannot express your query using other queryset methods.
> If you do need to use it, please [file a ticket](https://code.djangoproject.com/newticket) using the [QuerySet.extra
> keyword](https://code.djangoproject.com/query?keywords=~QuerySet.extra)
> with your use case (please check the list of existing tickets first) so
> that we can enhance the QuerySet API to allow removing `extra()`. We are
> no longer improving or fixing bugs for this method.
>
> 例如，`extra()` 的这种用法：
>
> ```pycon
> >>> qs.extra(
> ...     select={"val": "select col from sometable where othercol = %s"},
> ...     select_params=(someparam,),
> ... )
> ```
>
> 相当于：
>
> ```pycon
> >>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))
> ```
>
> 使用 [`RawSQL`](/zh-hans/6.0/ref/models/expressions/#django.db.models.expressions.RawSQL) 的主要好处是，如果需要的话，可以设置 `output_field`。主要的缺点是，如果你在原始 SQL 中引用了查询集的某个表的别名，那么 Django 有可能会改变这个别名（例如，当查询集在另一个查询中被用作子查询时）。

> **Warning**
>
> 每当你使用 `extra()` 时，你应该非常小心。每次使用它时，你应该使用 `params` 来转义任何用户可以控制的参数，以防止 SQL 注入攻击。
>
> 你也不能在 SQL 字符串中引用占位符。这个例子因为在 `%s` 周围的引号而容易受到 SQL 注入的影响。
>
> ```sql
> SELECT col FROM sometable WHERE othercol = '%s'  # unsafe!
> ```
>
> 你可以阅读更多关于 Django 的 [SQL 注入保护](/zh-hans/6.0/topics/security/#sql-injection-protection) 的工作原理。

根据定义，这些额外的查找可能无法移植到不同的数据库引擎中（因为你明确地编写了 SQL 代码），并且违反了 DRY 原则，所以你应该尽可能地避免它们。

指定 `params`、`select`、`where` 或 `tables` 中的一个或多个参数。这些参数都不是必须的，但你应该至少使用其中的一个。

- `select`

  The `select` argument lets you put extra fields in the `SELECT`
  clause. It should be a dictionary mapping attribute names to SQL
  clauses to use to calculate that attribute.

  举例：

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

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

  Django 将给定的 SQL 片段直接插入到 `SELECT` 语句中，所以上面例子的 SQL 结果将是这样的。

  ```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 结果是：

  ```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` 子句中不需要大多数数据库引擎在子查询周围所需的括号。

  在一些罕见的情况下，你可能希望在 `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：

  ```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`

  If you need to order the resulting queryset using some of the new
  fields or tables you have included via `extra()` use the `order_by`
  parameter to `extra()` and pass in a sequence of strings. These
  strings should either be model fields (as in the normal
  [`order_by()`](#django.db.models.query.QuerySet.order_by) method on querysets), of the form
  `table_name.column_name` or an alias for a column that you specified
  in the `select` parameter to `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"])
  ```

> **Warning**
>
> 如果你在 MySQL 上执行查询，请注意 MySQL 的静默强制类型转换可能会在混合类型时导致意外的结果。如果你在一个字符串类型的列上查询，但却有一个整数值，MySQL 会在执行比较之前将表中所有值的类型强制转换为整数。例如，如果你的表中包含值 `'abc'`、`'def'`，而你查询 `WHERE mycolumn=0`，这两行都会匹配。为了防止这种情况发生，在查询中使用该值之前，请执行正确的类型转换。

#### `defer()`

#### `defer(*fields)`

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

通过将不加载的字段名称传递给 `defer()`：

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

一个有递延字段的查询集仍然会返回模型实例。如果你访问每个递延字段，将从数据库中检索该字段（一次一个，而不是同时访问所有的递延字段）。

> **Note**
>
> 延迟加载的字段不会像这样从异步代码中惰性加载。相反，你将得到一个 `SynchronousOnlyOperation` 异常。如果你正在编写异步代码，不应尝试访问任何你已经使用 `defer()` 推迟加载的字段。

你可以多次调用 `defer()`。每次调用都会在推迟的集合中增加新的字段：

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

字段被添加到递延集的顺序并不重要。用已经被递延的字段名调用 `defer()` 是无害的（该字段仍将被递延）。

You can defer loading of fields in related models (if the related models are
loading via [`select_related()`](#django.db.models.query.QuerySet.select_related)) by using the standard double-underscore
notation to separate related fields:

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

如果你想清除一组递延字段，将 `None` 作为参数传递给 `defer()`：

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

Some fields in a model won't be deferred, even if you ask for them. You can
never defer the loading of the primary key. If you are using
[`select_related()`](#django.db.models.query.QuerySet.select_related) to retrieve related models, you shouldn't defer the
loading of the field that connects from the primary model to the related
one, doing so will result in an error.

Similarly, calling `defer()` (or its counterpart [`only()`](#django.db.models.query.QuerySet.only)) including an
argument from an aggregation (e.g. using the result of [`annotate()`](#django.db.models.query.QuerySet.annotate))
doesn't make sense: doing so will raise an exception. The aggregated values
will always be fetched into the resulting queryset.

> **Note**
>
> The `defer()` method (and its cousin, [`only()`](#django.db.models.query.QuerySet.only), below) are only for
> advanced use-cases. They provide an optimization for when you have analyzed
> your queries closely and understand *exactly* what information you need and
> have measured that the difference between returning the fields you need and
> the full set of fields for the model will be significant.
>
> 即使你认为自己处于高级用例情况下，**只有在在查询集加载时无法确定是否需要额外字段时才使用** `defer()`。如果你经常加载和使用数据的特定子集，你可以做出的最好选择是将模型进行规范化，并将未加载的数据放入一个单独的模型（和数据库表中）。如果出于某种原因列 *必须* 保留在一个表中，请创建一个具有 `Meta.managed = False` （请参阅 [`managed 属性`](/zh-hans/6.0/ref/models/options/#django.db.models.Options.managed) 文档）的模型，其中仅包含您通常需要加载和使用的字段，然后在可能会调用 `defer()` 的地方使用它。这使得你的代码对读者更加明确，速度略快，Python 进程中消耗的内存也略少。
>
> 例如，这两种模式都使用相同的基础数据库表：
>
> ```
> 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")
> ```
>
> 如果很多字段需要在非托管模型中重复，最好的办法是创建一个共享字段的抽象模型，然后让非托管模型和托管模型从抽象模型中继承。

> **Note**
>
> When calling [`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save) for instances with
> deferred fields, only the loaded fields will be saved. See
> [`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save) for more details.

#### `only()`

#### `only(*fields)`

`only()` 方法实际上是 [`defer()`](#django.db.models.query.QuerySet.defer) 的相反。只有传递到此方法中的字段，并且尚未指定为延迟加载的字段，在查询集评估时会立即加载。

如果你有一个几乎所有字段都需要延迟加载的模型，使用 `only()` 来指定补充的字段集合可以简化代码。

假设你有一个模型，其字段为 `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()`](#django.db.models.query.QuerySet.defer) 文档注释中的所有注意事项也适用于 `only()`。谨慎使用，只有在用尽其他选项后才能使用。

使用 `only()` 并省略使用 [`select_related()`](#django.db.models.query.QuerySet.select_related) 请求的字段也是错误的。另一方面，如果在没有任何参数的情况下调用 `only()`，将返回查询集提取的每个字段（包括注释）。

与 `defer()` 一样，你不能从异步代码中访问未加载的字段并期望它们加载。相反，你将得到一个 `SynchronousOnlyOperation` 异常。确保你可能访问的所有字段都在你的 `only()` 调用中。

> **Note**
>
> When calling [`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save) for instances with
> deferred fields, only the loaded fields will be saved. See
> [`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save) for more details.

> **Note**
>
> 在在 `only()` 之后使用 [`defer()`](#django.db.models.query.QuerySet.defer) 时，`defer` 中的字段将覆盖在两者中都列出的字段的 `only()`。

#### `using()`

#### `using(alias)`

This method is for controlling which database the `QuerySet` will be
evaluated against if you are using more than one database. The only argument
this method takes is the alias of a database, as defined in
[`DATABASES`](/zh-hans/6.0/ref/settings/#std-setting-DATABASES).

例如：

```pycon
# 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`](/zh-hans/6.0/ref/exceptions/#django.db.DatabaseError)。你也可以通过使用 `select_for_update( skip_locked=True)` 来忽略锁定的记录。`nowait` 和 `skip_locked` 是相互排斥的，在启用这两个选项的情况下调用 `select_for_update()` 会导致一个 [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)。

默认情况下，`select_for_update()` 锁定所有被查询选择的行。例如，在 [`select_related()`](#django.db.models.query.QuerySet.select_related) 中指定的相关对象的行，除了查询集模型的行之外，也会被锁定。如果不希望这样，可以在 `select_for_update(of=(...))` 中使用与 [`select_related()`](#django.db.models.query.QuerySet.select_related) 相同的字段语法指定你要锁定的相关对象。使用 `'self'` 来表示查询集的模型。

> **在 select_for_update(of=(...)) 中锁定父模型**
>
> 如果在使用 [多表继承](/zh-hans/6.0/topics/db/models/#multi-table-inheritance) 时要锁定父模型，必须在 `of` 参数中指定父链接字段（默认为 `<parent_model_name>_ptr`）。例如：
>
> ```
> Restaurant.objects.select_for_update(of=("self", "place_ptr"))
> ```

> **在指定的字段使用 select_for_update(of=(...))**
>
> 如果你想锁定模型并指定选定的字段，例如使用 [`values()`](#django.db.models.query.QuerySet.values)，你必须从每个模型的 `of` 参数中至少选择一个字段。没有选定字段的模型将不会被锁定。

仅在 PostgreSQL 上，你可以通过 `no_key=True` 来获得一个较弱的锁，这仍然允许在锁存在的情况下，创建仅仅引用锁定的行（例如，通过外键）。PostgreSQL 文档中有更多关于 [行级锁模式的细节](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS) 。

你不能在可空关联上使用 `select_for_update()`：

```pycon
>>> 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
```

为了避免这个限制，如果你不关心空对象，可以将它们排除在外：

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

`postgresql`、`oracle` 和 `mysql` 数据库后端支持 `select_for_update()`。然而，MariaDB 只支持 `nowait` 参数，MariaDB 10.6+ 还支持 `skip_locked` 参数，而 MySQL 支持 `nowait`、`skip_locked` 和 `of` 参数。`no_key` 参数仅在 PostgreSQL 上受支持。

在使用不支持这些选项的数据库后端（如 MySQL）向 ```select_for_update()``传递 ``nowait=True```、`skip_locked=True`、`no_key=True` 或 `of`，会产生一个 [`NotSupportedError`](/zh-hans/6.0/ref/exceptions/#django.db.NotSupportedError)。这可以防止代码意外地阻塞。

在支持 `SELECT ... FOR UPDATE` 的后端上，用 `select_for_update()` 在自动提交模式下执行一个查询集是一个 [`TransactionManagementError`](/zh-hans/6.0/ref/exceptions/#django.db.transaction.TransactionManagementError) 错误，因为在这种情况下行没有被锁定。如果允许这样做，这将促进数据损坏，并且很容易通过调用期望在一个事务之外的事务中运行的代码而引起。

在不支持 `SELECT ... FOR UPDATE` 的后端（比如 SQLite）使用 `select_for_update()` 不会有任何影响。`SELECT ... FOR UPDATE` 不会被添加到查询中，如果 `select_for_update()` 在自动提交模式下使用，也不会出现错误。

> **Warning**
>
> Although `select_for_update()` normally fails in autocommit mode, since
> [`TestCase`](/zh-hans/6.0/topics/testing/tools/#django.test.TestCase) automatically wraps each test in a
> transaction, calling `select_for_update()` in a `TestCase` even outside
> an [`atomic()`](/zh-hans/6.0/topics/db/transactions/#django.db.transaction.atomic) block will (perhaps unexpectedly)
> pass without raising a `TransactionManagementError`. To properly test
> `select_for_update()` you should use
> [`TransactionTestCase`](/zh-hans/6.0/topics/testing/tools/#django.test.TransactionTestCase).

> **可能不支持某些表达方式**
>
> PostgreSQL 不支持 `select_for_update()` 与 [`Window`](/zh-hans/6.0/ref/models/expressions/#django.db.models.expressions.Window) 表达式。

#### `raw()`

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

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

更多信息请参见 [执行原生 SQL 查询](/zh-hans/6.0/topics/db/sql/)。

> **Warning**
>
> `raw()` 总是触发一个新的查询，并且不考虑以前的过滤。因此，它通常应该从 `Manager` 或从一个新的 `QuerySet` 实例中调用。

### 返回新 `QuerySet` 的操作符

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

#### AND（`&`）

使用 SQL 的 `AND` 运算符以类似于链接过滤器的方式合并两个 `QuerySet`。

以下的都是相同的：

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

SQL 等价于：

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

#### OR（`|`）

使用 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 等价于：

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

`|` 不是一个换元运算，因为可能会产生不同的（虽然是等价的）查询。

#### XOR (`^`)

使用 SQL 的 `XOR` 运算符合并两个 `QuerySet`。`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 等价于：

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

> **Note**
>
> `XOR` 在 MariaDB 和 MySQL 上受到原生支持。在其他数据库上，`x ^ y ^ ... ^ z` 会被转换为等效的形式：
>
> ```sql
> (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
> )
> ```

### 不返回 `QuerySet` 的方法

以下 `QuerySet` 方法执行 `QuerySet`，并返回 `QuerySet` 以外的东西。

这些方法不使用缓存（参见 [缓存和 QuerySet](/zh-hans/6.0/topics/db/queries/#caching-and-querysets)）。相反，它们每次被调用时都会查询数据库。

因为这些方法评估了 QuerySet，它们是阻塞调用，因此它们的主要（同步）版本不能从异步代码中调用。因此，每个方法都有一个带有 `a` 前缀的相应异步版本 - 例如，你可以使用 `await aget(…)` 而不是 `get(…)`。

通常，除了它们的异步性质之外，它们的行为没有太大区别，但任何差异都在下面的方法旁边进行了说明。

#### `get()`

#### `get(*args, **kwargs)`

#### `aget(*args, **kwargs)`

*异步版本*: `aget()`

返回与给定的查找参数相匹配的对象，其格式应该在 [Field lookups](#id4) 中描述。你应该使用保证唯一的查询，比如主键或唯一约束中的字段。例如：

```
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`](/zh-hans/6.0/ref/models/class/#django.db.models.Model.DoesNotExist) 异常：

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

如果 `get()` 发现多个对象，会引发一个 [`Model.MultipleObjectsReturned`](/zh-hans/6.0/ref/models/class/#django.db.models.Model.MultipleObjectsReturned) 异常：

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

这两个异常类都是模型类的属性，并且特定于该模型。如果你想对不同模型的多个 `get()` 调用处理这样的异常，可以使用它们的通用基类。例如，你可以使用 [`django.core.exceptions.ObjectDoesNotExist`](/zh-hans/6.0/ref/exceptions/#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)`

*异步版本*: `acreate()`

A convenience method for creating an object and saving it all in one step.
Thus:

```
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](/zh-hans/6.0/ref/models/instances/#ref-models-force-insert) 参数在其他地方有说明，但它的意思是总是会创建一个新的对象。通常情况下，你不需要担心这个问题。但是，如果你的模型中包含了一个你设置的手动主键值，而且如果这个值已经存在于数据库中，那么对 `create()` 的调用就会以一个 [`IntegrityError`](/zh-hans/6.0/ref/exceptions/#django.db.IntegrityError) 失败，因为主键必须是唯一的。如果使用手动主键，要做好处理异常的准备。

#### `get_or_create()`

#### `get_or_create(defaults=None, **kwargs)`

#### `aget_or_create(defaults=None, **kwargs)`

*异步版本*: `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)},
)
```

Any keyword arguments passed to `get_or_create()` — *except* an optional one
called `defaults` — will be used in a [`get()`](#django.db.models.query.QuerySet.get) call. If an object is
found, `get_or_create()` returns a tuple of that object and `False`.

> **Warning**
>
> 假设数据库强制执行关键字参数的唯一性（参见 [`unique`](/zh-hans/6.0/ref/models/fields/#django.db.models.Field.unique) 或 [`unique_together`](/zh-hans/6.0/ref/models/options/#django.db.models.Options.unique_together)），这个方法是原子性的。如果关键字参数中使用的字段没有唯一性约束，那么对该方法的并发调用可能会导致插入具有相同参数的多条记录。

你可以通过将 `get_or_create()` 和 `filter()` 串联起来，并使用 [`Q 对象`](#django.db.models.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`](/zh-hans/6.0/ref/exceptions/#django.core.exceptions.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"})
```

The `get_or_create()` method has similar error behavior to [`create()`](#django.db.models.query.QuerySet.create)
when you're using manually specified primary keys. If an object needs to be
created and the key already exists in the database, an
[`IntegrityError`](/zh-hans/6.0/ref/exceptions/#django.db.IntegrityError) will be raised.

最后，关于在 Django 视图中使用 `get_or_create()` 的一些建议。请确保只在 `POST` 请求中使用它，除非你有充分的理由不这样做。`GET` 请求不应该对数据产生任何影响。相反，只有当对页面的请求对数据产生副作用时，才使用 `POST`。有关更多信息，请参阅 HTTP 规范中的 [**Safe methods**](https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1)。

> **Warning**
>
> 你可以通过 [`ManyToManyField`](/zh-hans/6.0/ref/models/fields/#django.db.models.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)
> ```
>
> 你可以通过 Book 的 chapters 字段使用 `get_or_create()`，但它只在该书的上下文中获取：
>
> ```pycon
> >>> 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
> ```
>
> This is happening because it's trying to get or create "Chapter 1" through
> the book "Ulysses", but it can't do either: the relation can't fetch that
> chapter because it isn't related to that book, but it can't create it either
> because `title` field should be unique.

#### `update_or_create()`

#### `update_or_create(defaults=None, create_defaults=None, **kwargs)`

#### `aupdate_or_create(defaults=None, create_defaults=None, **kwargs)`

*异步版本*: `aupdate_or_create()`

一个方便的方法，用于使用给定的 `kwargs` 更新对象，如果需要的话创建一个新对象。`create_defaults` 和 `defaults` 都是 (字段, 值) 对的字典。`create_defaults` 和 `defaults` 中的值可以是可调用的。`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()`](#django.db.models.query.QuerySet.get_or_create)。

如上文 [`get_or_create()`](#django.db.models.query.QuerySet.get_or_create) 中所述，这种方法容易出现竞争条件，如果不在数据库层面强制执行唯一性，就会导致同时插入多条记录。

就像 [`get_or_create()`](#django.db.models.query.QuerySet.get_or_create) 和 [`create()`](#django.db.models.query.QuerySet.create) 一样，如果你使用的是手动指定的主键，需要创建一个对象，但该键已经存在于数据库中，就会引发 [`IntegrityError`](/zh-hans/6.0/ref/exceptions/#django.db.IntegrityError)。

#### `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)`

*异步版本*: `abulk_create()`

这个方法以高效的方式将提供的对象列表插入数据库中（通常只有 1 个查询，无论有多少对象），并以与提供的顺序相同的顺序返回已创建的对象列表：

```pycon
>>> 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`](/zh-hans/6.0/ref/models/fields/#django.db.models.AutoField) or has
  a [`db_default`](/zh-hans/6.0/ref/models/fields/#django.db.models.Field.db_default) value, and `ignore_conflicts`
  is `False`, the primary key attribute can only be retrieved on certain
  databases (currently PostgreSQL, MariaDB, 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)
  ```

The `batch_size` parameter controls how many objects are created in a single
query. The default is to create as many objects in one batch as the database
will allow. (SQLite and Oracle limit the number of parameters in a query.)

在支持的数据库上（除了 Oracle），将 `ignore_conflicts` 参数设置为 `True` 告诉数据库忽略插入失败的行，例如违反唯一值约束的行。

在支持它的数据库上（除了 Oracle），将 `update_conflicts` 参数设置为 `True`，告诉数据库在冲突时更新 `update_fields`。在 PostgreSQL 和 SQLite 上，除了 `update_fields`，还必须提供可能冲突的 `unique_fields` 列表。

启用 `ignore_conflicts` 参数会禁用在每个模型实例上设置主键（如果数据库通常支持它）。

> **Warning**
>
> 在 MySQL 和 MariaDB 上，将 `ignore_conflicts` 参数设置为 `True` 将某些类型的错误，除了重复键之外，变成警告。即使在严格模式下也是如此。例如：无效值或不可空值违规。更多细节请参见 [MySQL documentation](https://dev.mysql.com/doc/refman/en/sql-mode.html#ignore-strict-comparison) 和 [MariaDB documentation](https://mariadb.com/kb/en/ignore/) 。

#### `bulk_update()`

#### `bulk_update(objs, fields, batch_size=None)`

#### `abulk_update(objs, fields, batch_size=None)`

*异步版本*: `abulk_update()`

这个方法高效地更新提供的模型实例上的给定字段，通常只需一个查询，并返回更新的对象数量：

```pycon
>>> 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()`](#django.db.models.query.QuerySet.update) 用于保存更改，所以这比遍历模型列表并对每个模型调用 `save()` 更有效，但它有一些注意事项：

- 你不能更新模型的主键。
- 每个模型的 `save()` 方法没有被调用，而且 [`pre_save`](/zh-hans/6.0/ref/signals/#django.db.models.signals.pre_save) 和 [`post_save`](/zh-hans/6.0/ref/signals/#django.db.models.signals.post_save) 信号没有被发送。
- 如果更新大量行中的大量列，生成的 SQL 可能非常大。通过指定一个合适的 `batch_size` 来避免这种情况。
- When updating a large number of objects, be aware that `bulk_update()`
  prepares all of the `WHEN` clauses for every object across all batches
  before executing any queries. This can require more memory than expected. To
  reduce memory usage, you can use an approach like this:

  ```
  from itertools import islice

  batch_size = 100
  ids_iter = iter(range(1000))
  while ids := list(islice(ids_iter, batch_size)):
      batch = Entry.objects.filter(id__in=ids)
      for entry in batch:
          entry.headline = f"Updated headline {entry.pk}"
      Entry.objects.bulk_update(batch, ["headline"], batch_size=batch_size)
  ```
- 更新定义在多表继承祖先上的字段将给每个祖先带来额外的查询。
- 当一个单独的批次包含重复的内容时，只有该批次的第一个实例会导致更新。
- 该函数返回的更新对象的数量可能少于传入的对象的数量。这可能是由于传入的对象重复，在同一批次中被更新，或者是竞赛条件，如对象在数据库中不再存在。

`batch_size` 参数控制一次查询中保存多少对象。默认值是在一个批次中更新所有对象，但 SQLite 和 Oracle 除外，它们对查询中使用的变量数量有限制。

#### `count()`

#### `count()`

#### `acount()`

*异步版本*: `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, * (Keyword-only parameters separator (PEP 3102)), field_name='pk')`

#### `ain_bulk(id_list=None, * (Keyword-only parameters separator (PEP 3102)), field_name='pk')`

*异步版本*: `ain_bulk()`

接收一个字段值的列表（`id_list`）和这些值的 `field_name`，并返回一个字典，将每个值映射到具有给定字段值的对象实例。`in_bulk` 不会引发任何 [`django.core.exceptions.ObjectDoesNotExist`](/zh-hans/6.0/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) 异常；也就是说，任何不匹配任何实例的 `id_list` 值将被简单地忽略掉。如果没有提供 `id_list`，将返回查询集的所有对象。`field_name` 必须是一个唯一字段或一个独立的字段（如果只有一个字段在 [`distinct()`](#django.db.models.query.QuerySet.distinct) 中指定）。`field_name` 默认为主键。

例如：

```pycon
>>> 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)`

*异步版本*: `aiterator()`

评估 `QuerySet` （通过执行查询）并返回结果的迭代器，如果调用其异步版本 `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. 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()` 与之前对 `prefetch_related()` 的调用兼容，只要提供了 `chunk_size`。较大的值将需要更少的查询来完成预取操作，但代价是更多的内存使用。

在某些数据库（例如 Oracle，SQLite）中，SQL 中的 `IN` 子句中的最大项数可能会受到限制。因此，应使用低于此限制的值。特别是在跨两个或多个关系进行预取的情况下，`chunk_size` 应该足够小，以便每个预取关系的预期结果数量仍然保持在限制以下。

只要 QuerySet 不预取任何相关对象，不为 `chunk_size` 提供值，Django 将使用默认的隐式值 2000。

根据数据库后端，查询结果将被一次性加载或使用服务器端的游标从数据库中流转。

##### 使用服务器端游标

Oracle 和 [PostgreSQL](/zh-hans/6.0/ref/databases/#postgresql-server-side-cursors) 使用服务器端的游标从数据库流式传输结果，而不需要将整个结果集加载到内存中。

Oracle 数据库驱动程序总是使用服务器端的游标。

对于服务器端的游标，`chunk_size` 参数指定了要在数据库驱动层缓存的结果数量。获取更大的块数会减少数据库驱动和数据库之间的往返次数，但会牺牲内存。

在 PostgreSQL 上，只有当 [`DISABLE_SERVER_SIDE_CURSORS`](/zh-hans/6.0/ref/settings/#std-setting-DATABASE-DISABLE_SERVER_SIDE_CURSORS) 设置为 `False` 时，才会使用服务器端游标。如果你使用的是配置在事务池模式下的连接池器，请阅读 [事务池和服务器端游标](/zh-hans/6.0/ref/databases/#transaction-pooling-server-side-cursors)。当禁用服务器端游标时，其行为与不支持服务器端游标的数据库相同。

##### 没有服务器端游标

MySQL 不支持流式结果，因此 Python 数据库驱动将整个结果集加载到内存中。然后数据库适配器使用 [**PEP 249**](https://peps.python.org/pep-0249/) 中定义的 `fetchmany()` 方法将结果集转化为 Python 行对象。

SQLite 可以使用 `fetchmany()` 分批获取结果，但由于 SQLite 不提供连接内查询之间的隔离，所以在向被迭代的表写入时要小心。参见 [使用 QuerySet.iterator() 时的隔离](/zh-hans/6.0/ref/databases/#sqlite-isolation) 了解更多信息。

`chunk_size` 参数控制 Django 从数据库驱动中获取的批次大小。批量越大，就会减少与数据库驱动通信的开销，但代价是略微增加内存消耗。

只要查询集不预取任何相关对象，不提供 `chunk_size` 的值将导致 Django 使用隐式默认值 2000，这个值是从 [psycopg 邮件列表上的计算](https://www.postgresql.org/message-id/4D2F2C71.8080805%40dndg.it) 推导出的。

> 假设行数为 10-20 列，文字数据和数字数据混合，2000 要取不到 100KB 的数据，这似乎是一个很好的折中方案，在传输的行数和提前退出循环时丢弃的数据之间。

#### `latest()`

#### `latest(*fields)`

#### `alatest(*fields)`

*异步版本*: `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](/zh-hans/6.0/topics/db/models/#meta-options) 指定了 [`get_latest_by`](/zh-hans/6.0/ref/models/options/#django.db.models.Options.get_latest_by)，你可以省略 `earliest()` 或 `latest()` 的任何参数。[`get_latest_by`](/zh-hans/6.0/ref/models/options/#django.db.models.Options.get_latest_by) 中指定的字段将被默认使用。

Like [`get()`](#django.db.models.query.QuerySet.get), `earliest()` and `latest()` raise
[`DoesNotExist`](/zh-hans/6.0/ref/models/class/#django.db.models.Model.DoesNotExist) if there is no object with the
given parameters.

请注意，`earliest()` 和 `latest()` 的存在纯粹是为了方便和可读性。

> **earliest() 和 latest() 可能返回日期为空的实例。**
>
> 由于排序是委托给数据库的，如果使用不同的数据库，允许空值的字段上的结果可能会有不同的排序。例如，PostgreSQL 和 MySQL 将空值排序为高于非空值，而 SQLite 则相反。
>
> 你可能想过滤掉空值：
>
> ```
> Entry.objects.filter(pub_date__isnull=False).latest("pub_date")
> ```

#### `earliest()`

#### `earliest(*fields)`

#### `aearliest(*fields)`

*异步版本*: `aearliest()`

除了方向改变外，其他工作方式都像 [`last()`](#django.db.models.query.QuerySet.last)。

#### `first()`

#### `first()`

#### `afirst()`

*异步版本*: `afirst()`

返回查询集匹配的第一个对象，如果没有匹配的对象，则返回 `None`。如果 `QuerySet` 没有定义排序，那么查询集自动按主键排序。这可能会影响聚合结果，如 [Interaction with order\_by()](/zh-hans/6.0/topics/db/aggregation/#aggregation-ordering-interaction) 中所述。

举例：

```
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()`

*异步版本*: `alast()`

Works like  [`first()`](#django.db.models.query.QuerySet.first), but returns the last object in the queryset.

#### `aggregate()`

#### `aggregate(*args, **kwargs)`

#### `aaggregate(*args, **kwargs)`

*异步版本*: `aaggregate()`

返回对 `QuerySet` 计算的聚合值（平均值、总和等）的字典。`aggregate()` 的每个参数都指定了一个将被包含在返回的字典中的值。

Django 提供的聚合函数在下面的 [Aggregation Functions](#id6) 中介绍。由于聚合函数也是 [查询表达式](/zh-hans/6.0/ref/models/expressions/)，所以你可以将聚合函数与其他聚合函数或值结合起来，创建复杂的聚合函数。

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

例如，当你处理博客条目时，你可能想要知道有多少位作者贡献了博客条目：

```pycon
>>> from django.db.models import Count
>>> Blog.objects.aggregate(Count("entry__authors"))
{'entry__authors__count': 16}
```

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

```pycon
>>> Blog.objects.aggregate(number_of_authors=Count("entry__authors"))
{'number_of_authors': 16}
```

关于聚合的深入讨论，见 [关于聚合的专题指南](/zh-hans/6.0/topics/db/aggregation/)。

#### `exists()`

#### `exists()`

#### `aexists()`

*异步版本*: `aexists()`

如果 [`QuerySet`](#django.db.models.query.QuerySet) 包含任何结果，则返回 `True`，如果不包含，则返回 `False`。该函数试图以最简单、最快速的方式执行查询，但它 *执行* 的查询与普通的 [`QuerySet`](#django.db.models.query.QuerySet) 查询几乎相同。

`existence()` 对于与 [`QuerySet`](#django.db.models.query.QuerySet) 中任何对象的存在有关的搜索很有用，特别是在一个大的 [`QuerySet`](#django.db.models.query.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)`

*异步版本*: `acontains()`

如果 [`QuerySet`](#django.db.models.query.QuerySet) 包含 `obj`，返回 `True`，如果不包含 `False`。这试图以最简单和最快的方式执行查询。

[`contains()`](#django.db.models.query.QuerySet.contains) 对于检查一个对象在 [`QuerySet`](#django.db.models.query.QuerySet) 中的成员资格很有用，特别是在一个大的 [`QuerySet`](#django.db.models.query.QuerySet) 的情况下。

要检查一个查询集是否包含一个特定的项目：

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

这将比以下需要执行和迭代整个查询集的方法更快：

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

像 [`exists()`](#django.db.models.query.QuerySet.exists) 一样，如果 `some_queryset` 还没有被执行，但你知道它将在某个时候被执行，那么使用 `some_queryset.contains(obj)` 将进行额外的数据库查询，通常会导致整体性能变慢。

#### `update()`

#### `update(**kwargs)`

#### `aupdate(**kwargs)`

*异步版本*: `aupdate()`

对指定的字段执行 SQL 更新查询，并返回匹配的行数（如果有些行已经有了新的值，则可能不等于更新的行数）。

例如，要关闭所有在 2010 年发布的博客条目的评论，你可以这样做：

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

（假定你的 `Entry` 模型有 `pub_date` 和 `comments_on`。）

你可以更新多个字段，没有限制。例如，这里我们更新了 `comments_on` 和 `headline` 字段：

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

`update()` 方法会立即应用，并且被更新的 [`QuerySet`](#django.db.models.query.QuerySet) 的唯一限制是它只能更新模型主表中的列，不能更新相关模型上的列。例如，你不能这样做：

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

基于相关字段的过滤仍然是可能的：

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

你不能在一个 [`QuerySet`](#django.db.models.query.QuerySet) 上调用 `update()`，因为它已经被取走了一个片断或者不能再被过滤。

`update()` 方法返回受影响的行数：

```pycon
>>> 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()` 之间的短暂时间内数据库中的某些东西可能发生变化的竞争条件。

> **MySQL does not support self-select updates**
>
> On MySQL, `QuerySet.update()` may execute a `SELECT` followed by an
> `UPDATE` instead of a single `UPDATE` when filtering on related tables,
> which can introduce a race condition if concurrent changes occur between
> the queries. To ensure atomicity, consider using transactions or avoiding
> such filter conditions on MySQL.

Finally, realize that `update()` does an update at the SQL level and, thus,
does not call any `save()` methods on your models, nor does it emit the
[`pre_save`](/zh-hans/6.0/ref/signals/#django.db.models.signals.pre_save) or
[`post_save`](/zh-hans/6.0/ref/signals/#django.db.models.signals.post_save) signals (which are a consequence of
calling [`Model.save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save)). If you want to
update a bunch of records for a model that has a custom
[`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save) method, loop over them and call
[`save()`](/zh-hans/6.0/ref/models/instances/#django.db.models.Model.save), like this:

```
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)
```

> **Note**
>
> `order_by()` 子句如果包含注释、继承字段或跨越关系的查找，将被忽略。

#### `delete()`

#### `delete()`

#### `adelete()`

*异步版本*: `adelete()`

对 [`QuerySet`](#django.db.models.query.QuerySet) 中的所有行执行 SQL 删除查询，并返回删除的对象数量和每个对象类型的删除数量的字典。

`delete()` 是即时应用的。你不能对已经被取走一个片断或不能再被过滤的 [`QuerySet`](#django.db.models.query.QuerySet) 调用 `delete()`。

例如，要删除特定博客中的所有条目：

```pycon
>>> 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`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey) 模拟了 SQL 约束 `ON DELETE CASCADE` — 也就是说，任何具有外键指向将要被删除的对象的对象将会随之一起被删除。例如：

```pycon
>>> 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`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey) 的 [`on_delete`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey.on_delete) 参数定义。

`delete()` 方法进行批量删除，并不调用模型上的任何 `delete()` 方法。但是，它确实为所有被删除的对象（包括级联删除）发出 [`pre_delete`](/zh-hans/6.0/ref/signals/#django.db.models.signals.pre_delete) 和 [`post_delete`](/zh-hans/6.0/ref/signals/#django.db.models.signals.post_delete) 信号。

Django 需要将对象获取到内存中来发送信号和处理级联。但是，如果没有级联和信号，那么 Django 可能会采取快速路径删除对象，而不需要将其获取到内存中。对于大面积的删除，这可以使内存使用量大大降低。也可以减少执行查询的数量。

设置为 [`on_delete`](/zh-hans/6.0/ref/models/fields/#django.db.models.ForeignKey.on_delete) `DO_NOTHING` 的外键不会阻止在删除时采取快速路径。

需要注意的是，对象删除中产生的查询是一个实现细节，可能会发生变化。

#### `as_manager()`

#### `classmethod as_manager()`

类方法，该方法返回一个 [`Manager`](/zh-hans/6.0/topics/db/managers/#django.db.models.Manager) 的实例，其中包含 `QuerySet` 的方法的副本。详见 [创建带有 QuerySet 方法的管理器](/zh-hans/6.0/topics/db/managers/#create-manager-with-queryset-methods) 。

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

#### `explain()`

#### `explain(format=None, **options)`

#### `aexplain(format=None, **options)`

*异步版本*: `aexplain()`

返回一个 `QuerySet` 的执行计划的字符串，它详细说明了数据库将如何执行查询，包括将使用的任何索引或联接。了解这些细节可以帮助你提高慢速查询的性能。

例如，在使用 PostgreSQL 时：

```pycon
>>> 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 除外，因为在那里的实现并不直接。

The `format` parameter changes the output format from the database's
default, which is usually text-based. PostgreSQL supports `'TEXT'`,
`'JSON'`, `'YAML'`, and `'XML'` formats. MariaDB and MySQL support
`'TEXT'` (also called `'TRADITIONAL'`) and `'JSON'` formats. MySQL
8.0.16+ also supports an improved `'TREE'` format, which is similar to
PostgreSQL's `'TEXT'` output and is used by default, if supported.

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

```pycon
>>> 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` 查询，也可能导致数据的改变。

> **Changed in Django 5.2**
>
> Support for the `memory` and `serialize` options on PostgreSQL 17+ was
> added.

### `Field` 查找

Field lookups are how you specify the meat of an SQL `WHERE` clause. They're
specified as keyword arguments to the `QuerySet` methods [`filter()`](#django.db.models.query.QuerySet.filter),
[`exclude()`](#django.db.models.query.QuerySet.exclude) and [`get()`](#django.db.models.query.QuerySet.get).

介绍见 [模型和数据库查询文档](/zh-hans/6.0/topics/db/queries/#field-lookups-intro)。

Django 的内置查找功能如下。也可以为模型字段写 [自定义查找](/zh-hans/6.0/howto/custom-lookups/)。

为方便起见，当没有提供查找类型时（如 `Entry.objects.get(id=14)`），查找类型被假定为 [`exact`](#std-fieldlookup-exact)。

#### `exact`

完全匹配。如果提供的比较值是 `None`，它将被解释为 SQL `NULL` （详见 [`isnull`](#std-fieldlookup-isnull)）。

举例：

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

SQL 等价于：

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

> **MySQL 比较**
>
> 在 MySQL 中，数据库表的“字符序”设置决定了 `act` 比较是否区分大小写。这是一个数据库设置，而 *不是* Django 设置。可以配置你的 MySQL 表来使用区分大小写的比较，但是会有一些折衷。关于这方面的更多信息，请参阅 [数据库](/zh-hans/6.0/ref/databases/) 文档中的 [字符序部分](/zh-hans/6.0/ref/databases/#mysql-collation)。

#### `iexact`

不区分大小写的完全匹配。如果提供的比较值是 `None`，它将被解释为 SQL `NULL` （详见 [`isnull`](#std-fieldlookup-isnull)）。

举例：

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

SQL 等价于：

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

注意第一个查询会匹配 `'Beatles Blog'`、`'beatles blog'`、`'BeAtLes BLoG'` 等。

> **SQLite 用户**
>
> 当使用 SQLite 后台和非 ASCII 字符串时，请记住 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching) 中关于字符串比较的内容。SQLite 对非 ASCII 字符串不进行区分大小写的匹配。

#### `contains`

区分大小写的包含测试。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

请注意，这将与标题 `'Lennon honored today'` 相匹配，而不是 `'lennon honored today'`。

> **SQLite 用户**
>
> SQLite 不支持区分大小写的 `LIKE` 语句；`contains` 的作用就像 SQLite 的 `icontains`。更多信息请参见 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching)。

#### `icontains`

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

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

> **SQLite 用户**
>
> 当使用 SQLite 后端和非 ASCII 字符串时，请记住 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching) 中关于字符串比较的内容。

#### `in`

在一个给定的可迭代对象中；通常是一个列表、元组或查询集。这不是一个常见的用例，但字符串（可迭代）是可以接受的。

举例：

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

SQL 等价于：

```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)
```

该查询集将作为子选择语句执行：

```sql
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 是惰性的](/zh-hans/6.0/topics/db/queries/#querysets-are-lazy)。

#### `gt`

大于。

举例：

```
Entry.objects.filter(id__gt=4)
```

SQL 等价于：

```sql
SELECT ... WHERE id > 4;
```

#### `gte`

大于等于。

#### `lt`

小于。

#### `lte`

小于等于

#### `startswith`

区分大小写的开头为。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

SQLite 不支持区分大小写的 `LIKE` 语句；`startswith` 的作用就像 SQLite 的 `istartswith`。

#### `istartswith`

不区分大小写的开头为。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

> **SQLite 用户**
>
> 当使用 SQLite 后端和非 ASCII 字符串时，请记住 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching) 中关于字符串比较的内容。

#### `endswith`

区分大小写的结尾为。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

> **SQLite 用户**
>
> SQLite 不支持区分大小写的 `LIKE` 语句；`endswith` 的作用类似于 SQLite 的 `iendswith`。更多内容请参考 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching) 文档。

#### `iendswith`

不区分大小写的结尾为。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

> **SQLite 用户**
>
> 当使用 SQLite 后端和非 ASCII 字符串时，请记住 [database note](/zh-hans/6.0/ref/databases/#sqlite-string-matching) 中关于字符串比较的内容。

#### `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 等价于：

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

在 SQL 中，你可以在任何你可以使用 `BETWEEN` 的地方使用 `range`——用于日期、数字甚至字符。

> **Warning**
>
> 用日期过滤 `DateTimeField` 不会包括最后一天的项目，因为界限被解释为“给定日期的 0 点”。如果 `pub_date` 是一个 `DateTimeField`，上面的表达式就会变成这个 SQL：
>
> ```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_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，字段在过滤前会被转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `year`

对于日期和日期时间字段，精确匹配年份。允许链接其他字段的查询。取整数年。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `iso_year`

对于日期和日期时间字段，精确的 ISO 8601 周号年份匹配。允许链接其他字段的查询。取整数年。

举例：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `month`

对于日期和日期时间字段，精确的月份匹配。允许链接其他字段的查询。取整数 1（1 月）到 12（12 月）。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `day`

对于日期和日期时间字段，精确匹配日期。允许链接其他字段的查询。取整数日。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

请注意，这将匹配任何带有 pub\_date 的月份第三天的记录，如 1 月 3 日，7 月 3 日等。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `week`

对于日期和日期时间字段，根据 [ISO-8601](https://en.wikipedia.org/wiki/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 代码片段）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `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_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `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 天是星期天。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `quarter`

对于日期和日期时间字段，“一年的四分之一”匹配。允许链接额外的字段查找。取 1 到 4 之间的整数值，代表一年中的季度。

检索第二季度（4 月 1 日至 6 月 30 日）的条目示例：

```
Entry.objects.filter(pub_date__quarter=2)
```

（由于不同的数据库引擎对相关查询的实现各不相同，因此本次查询不包含等效的 SQL 代码片段）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `time`

对于日期时间字段，将其值强制转换为时间。允许链式附加字段查找。取一个 [`datetime.time`](https://docs.python.org/3/library/datetime.html#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_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，字段在过滤前会被转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `hour`

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

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `minute`

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

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `second`

对于日期时间和时间字段，完全秒配。允许链式查找其他字段。取 0 到 59 之间的整数。

举例：

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

SQL 等价于：

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

（确切的 SQL 语法因每个数据库引擎而异）。

当 [`USE_TZ`](/zh-hans/6.0/ref/settings/#std-setting-USE_TZ) 为 `True` 时，日期时间字段会在过滤前转换为当前时区。这需要 [数据库中的时区定义](#database-time-zone-definitions)。

#### `isnull`

取 `True` 或 `False`，分别对应 `IS NULL` 和 `IS NOT NULL` 的 SQL 查询。

举例：

```
Entry.objects.filter(pub_date__isnull=True)
```

SQL 等价于：

```sql
SELECT ... WHERE pub_date IS NULL;
```

#### `regex`

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

正则表达式语法是使用中的数据库后端的语法。对于没有内置正则表达式支持的 SQLite 来说，这个功能是由（Python）用户定义的 REGEXP 函数提供的，因此正则表达式语法是 Python 的 `re` 模块的语法。

举例：

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

SQL 等价于：

```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 等价于：

```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` 模块中提供了以下聚合函数。关于如何使用这些聚合函数的细节，请参见 [关于聚合的主题指南](/zh-hans/6.0/topics/db/aggregation/)。参见 [`Aggregate`](/zh-hans/6.0/ref/models/expressions/#django.db.models.Aggregate) 文档，了解如何创建你的聚合函数。

> **Warning**
>
> SQLite 无法处理日期／时间字段的聚合。这是因为 SQLite 中没有原生的日期／时间字段，而 Django 目前使用文本字段来模拟这些功能。试图在 SQLite 中使用日期／时间字段上的聚合将引发 `NotSupportedError`。

> **空的查询集或分组**
>
> 聚合函数在与空的 `QuerySet` 或分组一起使用时会返回 `None`。例如，如果 `QuerySet` 不包含任何条目或在非空的 `QuerySet` 中有任何空分组时，`Sum` 聚合函数将返回 `None` 而不是 `0`。要返回另一个值，可以定义 `default` 参数。 `Count` 是这种行为的一个例外；如果 `QuerySet` 为空，它将返回 `0`，因为 `Count` 不支持 `default` 参数。

所有聚合体都有以下共同的参数：

#### `expressions`

引用模型上的字段的字符串，字段的转换，或 [查询表达式](/zh-hans/6.0/ref/models/expressions/)。

#### `output_field`

一个可选的参数，表示返回值的 [模型字段](/zh-hans/6.0/ref/models/fields/)

> **Note**
>
> 当组合多个字段类型时，Django 只能在所有字段类型相同的情况下确定 `output_field`。否则，你必须自己提供 `output_field`。

#### `filter`

一个可选的 [`Q 对象`](#django.db.models.Q)，用于过滤被聚合的行。

参见 [条件聚合](/zh-hans/6.0/ref/models/conditional-expressions/#conditional-aggregation) 和 [过滤注解](/zh-hans/6.0/topics/db/aggregation/#filtering-on-annotations) 的用法示例。

#### `default`

一个可选的参数，允许指定一个值作为默认值，当查询集（或分组）不包含条目时使用。

#### `**extra`

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

#### `AnyValue`

> **New in Django 6.0**

#### `class AnyValue(expression, output_field=None, filter=None, default=None, **extra)`

Returns an arbitrary value from the non-null input values.

- Default alias: `<field>__anyvalue`
- 返回类型：与输入字段相同，或者如果提供了 `output_field`，则返回它。如果查询集或分组为空，将返回 `default`。

用法示例：

```pycon
>>> # Get average rating for each year along with a sample headline
>>> # from that year.
>>> from django.db.models import AnyValue, Avg, F, Q
>>> sample_headline = AnyValue("headline")
>>> Entry.objects.values(
...     pub_year=F("pub_date__year"),
... ).annotate(
...     avg_rating=Avg("rating"),
...     sample_headline=sample_headline,
... )

>>> # Get a sample headline from each year with rating greater than 4.5.
>>> sample_headline = AnyValue(
...     "headline",
...     filter=Q(rating__gt=4.5),
... )
>>> Entry.objects.values(
...     pub_year=F("pub_date__year"),
... ).annotate(
...     avg_rating=Avg("rating"),
...     sample_headline=sample_headline,
... )
```

Supported on SQLite, MySQL, Oracle, and PostgreSQL 16+.

> **MySQL with ONLY_FULL_GROUP_BY enabled**
>
> When the `ONLY_FULL_GROUP_BY` SQL mode is enabled on MySQL it may be
> necessary to use `AnyValue` if an aggregation includes a mix of
> aggregate and non-aggregate functions. Using `AnyValue` allows the
> non-aggregate function to be referenced in the select list when
> database cannot determine that it is functionally dependent on the
> columns in the [group by](https://dev.mysql.com/doc/refman/8.4/en/group-by-handling.html) clause. See the [aggregation
> documentation](/zh-hans/6.0/topics/db/aggregation/#aggregation-mysql-only-full-group-by) for more details.

#### `Avg`

#### `class Avg(expression, output_field=None, distinct=False, filter=None, default=None, **extra)`

返回给定表达式的平均值，除非指定不同的 `output_field`，否则必须是数值。

- 默认别名：`<field>__avg`
- 返回类型：如果输入是 `int`，则返回 `float`，否则返回与输入字段相同的类型，或者如果提供了 `output_field`，则返回它。如果查询集或分组为空，将返回 `default`。

#### `distinct`

可选。如果 `distinct=True`，则 `Avg` 返回唯一值的平均值。这相当于 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`。

> **Note**
>
> 不支持 `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`
- 返回类型：如果输入是 `int`，则返回 `float`，否则返回与输入字段相同的类型，或者如果提供了 `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=True`，`Sum` 返回唯一值的总和。这相当于 SQL 中的 `SUM(DISTINCT <field>)`。默认值是 `False`。

#### `Variance`

#### `class Variance(expression, output_field=None, sample=False, filter=None, default=None, **extra)`

返回给定表达式中数据的方差。

- 默认别名：`<field>__variance`
- 返回类型：如果输入是 `int`，则返回 `float`，否则返回与输入字段相同的类型，或者如果提供了 `output_field`，则返回它。如果查询集或分组为空，将返回 `default`。

#### `sample`

可选。默认情况下，`Variance` 返回总体方差。然而，如果 `sample=True`，返回值将是样本方差。

#### `StringAgg`

> **New in Django 6.0**

#### `class StringAgg(expression, delimiter, output_field=None, distinct=False, filter=None, order_by=None, default=None, **extra)`

返回输入值串联成的字符串，用 `delimiter` 字符串分隔，如果没有值，则返回 `default`。

- Default alias: `<field>__stringagg`
- Return type: `string` or `output_field` if supplied. If the
  queryset or grouping is empty, `default` is returned.

#### `delimiter`

A `Value` or expression representing the string that should separate
each of the values. For example, `Value(",")`.

## 查询相关工具

本节提供了与查询相关的工具的参考资料，其他地方没有记载。

### `Q()` 对象

#### `class Q`

`Q()` 对象表示可用于数据库相关操作的 SQL 条件。 它类似于 F() \<django.db.models.F\>\` 对象表示模型字段或注释的值的方式。 它们使得定义和重用条件成为可能。 这些可以使用“~”（“NOT”）运算符进行否定，并使用“|”（“OR”）、“&”（“AND”）等运算符进行组合 ) 和\`\`^\`\` (`XOR`)。 请参阅：ref:complex-lookups-with-q。

### `Prefetch()` 对象

#### `class Prefetch(lookup, queryset=None, to_attr=None)`

The `Prefetch()` object can be used to control the operation of
[`prefetch_related()`](#django.db.models.query.QuerySet.prefetch_related).

The `lookup` argument describes the relations to follow and works the same
as the string based lookups passed to
[`prefetch_related()`](#django.db.models.query.QuerySet.prefetch_related). For example:

```pycon
>>> from django.db.models import Prefetch
>>> Question.objects.prefetch_related(Prefetch("choice_set")).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
# This will only execute two queries regardless of the number of Question
# and Choice objects.
>>> Question.objects.prefetch_related(Prefetch("choice_set"))
<QuerySet [<Question: What's up?>]>
```

The `queryset` argument supplies a base `QuerySet` for the given lookup.
This is useful to further filter down the prefetch operation, or to call
[`select_related()`](#django.db.models.query.QuerySet.select_related) from the prefetched
relation, hence reducing the number of queries even further:

```pycon
>>> voted_choices = Choice.objects.filter(votes__gt=0)
>>> voted_choices
<QuerySet [<Choice: The sky>]>
>>> prefetch = Prefetch("choice_set", queryset=voted_choices)
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: The sky>]>
```

`to_attr` 参数将预取操作的结果设置为自定义属性：

```pycon
>>> prefetch = Prefetch("choice_set", queryset=voted_choices, to_attr="voted_choices")
>>> Question.objects.prefetch_related(prefetch).get().voted_choices
<QuerySet [<Choice: The sky>]>
>>> Question.objects.prefetch_related(prefetch).get().choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
```

> **Note**
>
> 当使用 `to_attr` 时，预取结果存储在列表中。 与传统的 `prefetch_related` 调用相比，这可以显着提高速度，传统的 `prefetch_related` 调用将缓存的结果存储在 `QuerySet` 实例中。

### `prefetch_related_objects()`

#### `prefetch_related_objects(model_instances, *related_lookups)`

#### `aprefetch_related_objects(model_instances, *related_lookups)`

*异步版本*：`aprefetch_related_objects()`

在作为模型实例的可迭代对象上预取给定的查找。这在接收模型实例列表而不是 `QuerySet` 的代码中很有用；例如，从缓存中获取模型或手动实例化它们时。

Pass an iterable of model instances (must all be of the same class and able to
be iterated multiple times) and the lookups or [`Prefetch`](#django.db.models.Prefetch) objects you
want to prefetch for. For example:

```pycon
>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache()  # A list of Restaurants
>>> prefetch_related_objects(restaurants, "pizzas__toppings")
```

当使用 `prefetch_related_objects` 的多个数据库时，预取查询将使用与模型实例相关的数据库。这可以通过在相关查找中使用自定义查询集来覆盖。

### `FilteredRelation()` 对象

#### `class FilteredRelation(relation_name, * (Keyword-only parameters separator (PEP 3102)), condition=Q())`

#### `relation_name`

你想过滤关系的字段名。

#### `condition`

一个 [`Q`](#django.db.models.Q) 对象来控制过滤。

`FilteredRelation` is used with [`annotate()`](#django.db.models.query.QuerySet.annotate) to create an
`ON` clause when a `JOIN` is performed. It doesn't act on the default
relationship but on the annotation name (`pizzas_vegetarian` in example
below).

例如，要查找具有在名称中包含 `'mozzarella'` 的素食比萨的餐馆：

```pycon
>>> from django.db.models import FilteredRelation, Q
>>> Restaurant.objects.annotate(
...     pizzas_vegetarian=FilteredRelation(
...         "pizzas",
...         condition=Q(pizzas__vegetarian=True),
...     ),
... ).filter(pizzas_vegetarian__name__icontains="mozzarella")
```

如果有大量的比萨，这个查询集的性能要优于：

```pycon
>>> Restaurant.objects.filter(
...     pizzas__vegetarian=True,
...     pizzas__name__icontains="mozzarella",
... )
```

因为第一个查询集的 `WHERE` 子句中的过滤只对素食披萨进行操作。

`FilteredRelation` 不支持：

- [`QuerySet.only()`](#django.db.models.query.QuerySet.only) 和 [`prefetch_related()`](#django.db.models.query.QuerySet.prefetch_related)。
- 一个从父模型继承的 [`GenericForeignKey`](/zh-hans/6.0/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey)。
