# Django 5.2.8 documentation

# Django 4.1 版本发行说明

2022 年 8 月 3 日

欢迎使用 Django 4.1！

这些发布说明涵盖了 新功能，以及从 Django 4.0 或更早版本升级时需要注意的一些 不兼容变更。我们已经 开始了某些功能的弃用过程。

如果你要更新现有的项目，请看 如何将 Django 更新至新的版本 指南。

## Python 兼容性

Django 4.1 支持 Python 3.8、3.9、3.10 和 3.11（从 4.1.3 开始）。我们 强烈建议 并且只官方支持每个系列的最新发布版本。

## Django 4.1 新特性

### 基于类的视图的异步处理程序。

现在，视图的子类可以定义异步的 HTTP 方法处理程序：

    import asyncio
    from django.http import HttpResponse
    from django.views import View

    class AsyncView(View):
        async def get(self, request, *args, **kwargs):
            # Perform view logic using await.
            await asyncio.sleep(1)
            return HttpResponse("Hello async world!")

请参阅 异步类视图 以获取更多详细信息。

### 异步的 ORM 接口。

`QuerySet` 现在为所有数据访问操作提供了异步接口。这些接口的命名方式与现有的同步操作相同，但带有一个 `a` 前缀，例如 `acreate()`、`aget()` 等等。

新的接口允许您编写异步代码，而无需将 ORM 操作包装在 `sync_to_async()` 中：

    async for author in Author.objects.filter(name__startswith="A"):
        book = await author.books.afirst()

值得注意的是，目前数据库操作仍然是同步的，但正在进行贡献工作，以将异步支持推向 SQL 编译器并集成异步数据库驱动程序。新的异步查询集接口目前为您封装了必要的 `sync_to_async()` 操作，将允许您的代码充分利用 ORM 异步支持的发展。

请参阅 异步查询 以获取详细信息和限制。

### 约束的验证

在 `Meta.constraints` 选项中定义的 `Check`、`unique` 和 `exclusion` 约束现在在 模型验证 期间进行检查。

### 表单渲染的可访问性

为了帮助使用屏幕阅读器和其他辅助技术的用户，从这个版本开始提供了基于 `<div>` 的新表单模板。这些模板提供比旧模板更可访问的导航，并能够正确地将相关控件（如单选列表）分组到字段集中。

推荐使用新模板，并且在 Django 5.0 中，当在模板中输出表单时（如 `{{ form }}`），新模板将成为默认的表单呈现样式。

为了方便采用新的输出样式，现在可以通过项目级别的 `FORM_RENDERER` 设置来配置默认的表单和表单集模板。

请查看 下面的表单部分 以获取完整的详细信息。

### `CSRF_COOKIE_MASKED` 设置

新的 `CSRF_COOKIE_MASKED` 过渡性设置允许指定是否要对 CSRF cookie 进行掩码处理。

`CsrfViewMiddleware` 不再像它在 DOM 中处理 CSRF 令牌一样对 CSRF cookie 进行掩码处理。如果你正在将同一项目的多个实例升级到 Django 4.1，你应该在过渡期间将 `CSRF_COOKIE_MASKED` 设置为 `True`，以便与旧版本的 Django 兼容。一旦升级到 4.1 完成，你可以停止覆盖 `CSRF_COOKIE_MASKED`。

该设置在此版本中已被弃用，并将在 Django 5.0 中移除。

### 次要特性

#### `django.contrib.admin`

- 管理员 深色模式 CSS 变量 现在应用在一个单独的样式表和模板块中。

- 提供自定义 `FieldListFilter` 子类的 ModelAdmin 列表过滤器 现在可以在使用 `__in` 查询时控制查询字符串值的分隔符，用于多个值的过滤。

- 管理员的 `history view` 现在支持分页。

- 相关的小部件包装现在有一个指向对象修改表单的链接。

- `AdminSite.get_app_list()` 方法现在允许更改管理员首页上应用程序和模型的顺序。

#### `django.contrib.auth`

- PBKDF2 密码哈希器的默认迭代次数从 320 , 000 增加到 390 , 000 。

- `RemoteUserBackend.configure_user()` 方法现在允许将用户属性与远程系统（如 LDAP 目录）中的属性同步。

#### `django.contrib.gis`

- The new `GEOSGeometry.make_valid()` method allows converting invalid geometries to valid ones.

- `GEOSGeometry.normalize()` 的新参数 `clone` 允许创建几何图形的归一化克隆。

#### `django.contrib.postgres`

- 新的 `BitXor()` 聚合函数返回所有非空输入值的按位 `XOR` 的 `int` 值。

- `SpGistIndex` 现在在 PostgreSQL 14+ 上支持覆盖索引。

- `ExclusionConstraint` 现在在 PostgreSQL 14+ 上支持使用 SP-GiST 索引的覆盖排除约束。

- 新的 `DateTimeRangeField` 和 `DecimalRangeField` 的 `default_bounds` 属性允许为列表和元组输入指定边界。

- `ExclusionConstraint` 现在允许使用 `OpClass()` 表达式指定操作符类。

#### `django.contrib.sitemaps`

- 默认的站点地图索引模板 `<sitemapindex>` 现在在可用时包括 `<lastmod>` 时间戳，通过新的 `get_latest_lastmod()` 方法。自定义站点地图索引模板应该根据调整后的 上下文变量 进行更新。

#### `django.contrib.staticfiles`

- `ManifestStaticFilesStorage` 现在会将 CSS 源映射引用的路径替换为它们的哈希版本。

#### 数据库后端

- 第三方数据库后端现在可以使用 `DatabaseFeatures.minimum_database_version` 属性指定数据库的最低要求版本，它是一个元组（例如 `(10, 0)` 表示 "10.0"）。如果指定了最低版本，后端还必须实现 `DatabaseWrapper.get_database_version()`，该方法返回当前数据库版本的元组。后端的 `DatabaseWrapper.init_connection_state()` 方法必须调用 `super()` 以便进行版本检查。

#### 表单

- 渲染表单时默认使用的模板，例如在模板中作为 `{{ form }}` 显示，现在可以在项目级别通过在提供给 `FORM_RENDERER` 的类上设置 `form_template_name` 来配置。

  `Form.template_name` 现在是一个属性，延迟到渲染器，但可以用一个字符串值覆盖，以指定每个表单类的模板名称。

  同样，可以通过匹配的 `formset_template_name` 渲染器属性来指定用于渲染表单集的默认模板。

- 新的 `div.html` 表单模板引用了 `Form.template_name_div` 属性，并与 `Form.as_div()` 方法匹配，使用 HTML `<div>` 元素来渲染表单。

  推荐使用这种新的输出样式，而不是现有的 `as_table()`、`as_p()` 和 `as_ul()` 样式，因为模板实现了 `<fieldset>` 和 `<legend>` 来组合相关的输入，对屏幕阅读器用户更容易导航。

  从 Django 5.0 开始，基于 div 的输出将成为默认的渲染样式。

- 为了平稳过渡到新的 `<div>` 输出样式，提供了两个过渡性的表单渲染器类：`django.forms.renderers.DjangoDivFormRenderer` 和 `django.forms.renderers.Jinja2DivFormRenderer`，分别适用于 Django 和 Jinja2 模板后端。

  您可以通过 `FORM_RENDERER` 设置之一来应用其中之一。例如：

      FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"

  一旦 `<div>` 输出样式成为默认样式（从 Django 5.0 开始），这些过渡渲染器将被弃用，并计划在 Django 6.0 中移除。届时可以删除 `FORM_RENDERER` 声明。

- 如果新的 `<div>` 输出样式不适用于您的项目，您应该定义一个渲染器子类，指定 `form_template_name` 和 `formset_template_name` 以适应您所需的样式，并相应地设置 `FORM_RENDERER`。

  例如，对于 `as_p()` 使用的 `<p>` 输出样式，您可以定义一个表单渲染器设置，将 `form_template_name` 设置为 `"django/forms/p.html"`，将 `formset_template_name` 设置为 `"django/forms/formsets/p.html"`。

- 新的 `legend_tag()` 允许通过 `label_tag()` 的新 `tag` 参数以 `<legend>` 标签方式呈现字段标签。

- 对于 `modelformset_factory()` 和 `inlineformset_factory()`，新的 `edit_only` 参数允许防止创建新对象。

- 媒体 的 `js` 和 `css` 类属性现在允许使用可散列的对象，而不仅仅是路径字符串，只要这些对象实现了 `__html__()` 方法（通常在使用 `html_safe()` 装饰器时）。

- 新的 `BoundField.use_fieldset` 和 `Widget.use_fieldset` 属性有助于识别那些应该在 `<fieldset>` 中与 `<legend>` 一起分组的小部件。

- `BaseFormSet` 的 error_messages 参数现在允许通过传递 `'too_few_forms'` 和 `'too_many_forms'` 键来自定义无效表单数量的错误消息。

- `IntegerField`、`FloatField` 和 `DecimalField` 现在可以选择接受一个 `step_size` 参数。这用于设置 `step` HTML 属性，并在表单提交时进行验证。

#### 国际化

- `i18n_patterns()` 函数现在支持同时包含脚本和区域的语言。

#### 管理命令

- `makemigrations --no-input` 现在记录默认答案和无法创建迁移的原因。

- 新的 `makemigrations --scriptable` 选项将日志输出和输入提示重定向到 `stderr`，仅将生成的迁移文件的路径写入 `stdout`。

- 新的 `migrate --prune` 选项允许从 `django_migrations` 表中删除不存在的迁移。

- 由 `startproject`、`startapp`、`optimizemigration`、`makemigrations` 和 `squashmigrations` 创建的 Python 文件现在如果在您的 `PATH` 上存在 `black` 命令，将会使用它进行格式化。

- 新的 `optimizemigration` 命令允许优化迁移操作。

#### 迁移

- 新的 `RenameIndex` 操作允许重命名在 `Meta.indexes` 或 `index_together` 选项中定义的索引。

- 迁移自动检测器现在在重命名 `Meta.indexes` 中定义的索引时，生成 `RenameIndex` 操作，而不是 `RemoveIndex` 和 `AddIndex`。

- 迁移自动检测器现在会在将 `Meta.index_together` 中定义的索引移动到 `Meta.indexes` 时生成 `RenameIndex` 操作，而不是 `AlterIndexTogether` 和 `AddIndex`。

#### 模型

- `Window` 表达式的 `order_by` 参数现在可以接受对字段和转换的字符串引用。

- 新的 `CONN_HEALTH_CHECKS` 设置允许启用对 持久数据库连接 进行健康检查，以减少失败的请求次数，例如在数据库服务器重新启动后。

- 现在，当插入一行时违反唯一约束时，`QuerySet.bulk_create()` 支持更新字段。这在 MariaDB、MySQL、PostgreSQL 和 SQLite 3.24+ 上都受支持。

- `QuerySet.iterator()` 现在支持在提供了 `chunk_size` 参数的情况下预取相关对象。在旧版本中，不进行预取。

- `Q` 对象和查询集现在可以使用 `^` 作为异或（`XOR`）运算符进行组合。`XOR` 在 MariaDB 和 MySQL 上有本地支持。对于不支持 `XOR` 的数据库，查询将被转换为使用 `AND`、`OR` 和 `NOT` 的等效查询。

- 新的 Field.non_db_attrs 属性允许自定义不影响列定义的字段属性。

- 在 PostgreSQL 上，`AutoField`、`BigAutoField` 和 `SmallAutoField` 现在作为标识列（identity columns）创建，而不是带有序列的序列列（serial columns）。

#### 请求和响应

- `HttpResponse.set_cookie()` 现在支持 `timedelta` 对象作为 `max_age` 参数。

#### 安全

- 新的 `SECRET_KEY_FALLBACKS` 设置允许提供一组值用于密钥轮换。

- `SECURE_PROXY_SSL_HEADER` 设置现在支持在头部值中以逗号分隔的协议列表。

#### 信号

- `pre_delete` 和 `post_delete` 信号现在会分发删除的 `origin`。

#### 模板

- 在包装 `json_script` 模板过滤器时，不再需要 HTML `<script>` 元素的 `id` 属性。

- 在开发环境中，当 `DEBUG` 为 `True` 且未指定 `OPTIONS['loaders']` 时，现在会启用 `cached template loader`。如果需要，您可以指定 `OPTIONS['loaders']` 来覆盖这个设置。

#### 测试

- `DiscoverRunner` 现在支持在 macOS、Windows 和任何默认 `multiprocessing` 启动方法为 `spawn` 的系统上并行运行测试。

- `django.test.TestCase` 中标记为持久的嵌套原子块现在会引发 `RuntimeError`，与测试外部相同。

- `SimpleTestCase.assertFormError()` 和 `assertFormsetError()` 现在支持直接传递表单/表单集对象。

#### URLs

- 新的 `ResolverMatch.captured_kwargs` 属性存储了从 URL 解析的捕获的关键字参数。

- 新的 `ResolverMatch.extra_kwargs` 属性存储了传递给视图函数的额外关键字参数。

#### 实用程序

- `SimpleLazyObject` 现在支持加法操作。

- `mark_safe()` 现在保留懒惰对象。

#### 验证器

- 新的 `StepValueValidator` 用于检查一个值是否是给定步长的整数倍。这个新的验证器用于表示数值的表单字段的新参数 `step_size`。

## 4.1 版本中的不兼容变更

### 数据库后端 API

本节介绍了第三方数据库后端可能需要的更改。

- `BaseDatabaseFeatures.has_case_insensitive_like` 从 `True` 改为 `False`，以反映大多数数据库的行为。

- `DatabaseIntrospection.get_key_columns()` 已被移除。请改用 `DatabaseIntrospection.get_relations()`。

- `DatabaseOperations.ignore_conflicts_suffix_sql()` 方法被替换为 `DatabaseOperations.on_conflict_suffix_sql()`，它接受 `fields`、`on_conflict`、`update_fields` 和 `unique_fields` 参数。

- `DatabaseOperations.insert_statement()` 方法的 `ignore_conflicts` 参数被替换为接受 `django.db.models.constants.OnConflict` 的 `on_conflict` 参数。

- `DatabaseOperations._convert_field_to_tz()` 被替换为 `DatabaseOperations._convert_sql_to_tz()`，它接受 `sql`、`params` 和 `tzname` 参数。

- `DatabaseOperations` 上的多个日期和时间方法现在接受 `sql` 和 `params` 参数，而不再接受 `field_name`，并返回包含一些 SQL 和要插入该 SQL 的参数的 2 元组。已更改的方法具有以下新签名：

  - `DatabaseOperations.date_extract_sql(lookup_type, sql, params)`

  - `DatabaseOperations.datetime_extract_sql(lookup_type, sql, params, tzname)`

  - `DatabaseOperations.time_extract_sql(lookup_type, sql, params)`

  - `DatabaseOperations.date_trunc_sql(lookup_type, sql, params, tzname=None)`

  - `DatabaseOperations.datetime_trunc_sql(self, lookup_type, sql, params, tzname)`

  - `DatabaseOperations.time_trunc_sql(lookup_type, sql, params, tzname=None)`

  - `DatabaseOperations.datetime_cast_date_sql(sql, params, tzname)`

  - `DatabaseOperations.datetime_cast_time_sql(sql, params, tzname)`

### `django.contrib.gis`

- 移除对 GDAL 2.1 的支持。

- 移除对 PostGIS 2.4 的支持。

### 不再支持 PostgreSQL 10 。

PostgreSQL 10 的上游支持将在 2022 年 11 月结束。 Django 4.1 支持 PostgreSQL 11 及更高版本。

### 不再支持 MariaDB 10.2

MariaDB 10.2 的上游支持将在 2022 年 5 月结束。 Django 4.1 支持 MariaDB 10.3 及更高版本。

### 管理后台的变更列表搜索跨多值关系的变更

管理员 changelist 使用多个搜索词进行搜索现在在单个调用 `filter()` 中应用，而不是在连续的 `filter()` 调用中应用。

对于多值关系，这意味着来自相关模型的行必须匹配所有词项，而不是任何词项。例如，如果 `search_fields` 设置为 `['child__name', 'child__age']`，用户搜索 `'Jamal 17'`，那么只有与一些名为 Jamal 的 17 岁孩子存在关系的父母行才会被返回，而不会返回仅仅因为有一个名为 Jamal 的更年轻或更年长的孩子以及其他一些 17 岁孩子的父母。

有关这种差异的更多讨论，请参阅 跨多值关联 主题。在 Django 4.0 及更早版本中，`get_search_results()` 遵循第二个示例查询，但这种未记录的行为导致了具有过多连接的查询。

### 未保存的模型实例的反向外键变更

为了统一与未保存的模型实例的多对多关系的行为，反向外键现在在调用未保存对象的 `related managers` 时会引发 `ValueError`。

### 杂项

- `ForeignKey`、`ManyToManyField` 和 `GenericRelation` 的相关管理器现在被缓存在它们所属的 `Model` 实例上。这个变更在 Django 4.1.2 中被撤销了。

- `DiscoverRunner` now returns a non-zero error code for unexpected successes from tests marked with `unittest.expectedFailure()`.

- `CsrfViewMiddleware` 现在不再像在 DOM 中遮蔽 CSRF 令牌一样遮蔽 CSRF cookie。

- `CsrfViewMiddleware` 现在使用 `request.META['CSRF_COOKIE']` 来存储未遮蔽的 CSRF 密钥，而不是遮蔽版本。这是一个未记录的、私有的 API。

- `ModelAdmin.actions` 和 `inlines` 属性现在默认为空元组，而不是空列表，以防止意外的变更。

- 在 CSS 表单媒体 的 `<link>` 标签中不再包含 `type="text/css"` 属性。

- `formset:added` 和 `formset:removed` JavaScript 事件现在是纯 JavaScript 事件，不依赖于 jQuery。有关此更改的更多详细信息，请参阅 内联表单事件。

- 未记录的 `django.utils.log.log_response()` 函数的 `exc_info` 参数已被替换为 `exception`。

- 未记录的 `django.views.static.was_modified_since()` 函数的 `size` 参数已被移除。

- 管理员注销界面现在使用 `POST` 请求。

- 未记录的 `InlineAdminFormSet.non_form_errors` 属性已被替换为 `non_form_errors()` 方法。这与 `BaseFormSet` 保持一致。

- 根据 上面，在开发中现在启用了缓存模板加载器。如果有必要，你可以指定 `OPTIONS['loaders']` 来覆盖这个设置。

- 未记录的 `django.contrib.auth.views.SuccessURLAllowedHostsMixin` 混合类已被替换为 `RedirectURLMixin`。

- `BaseConstraint` 的子类必须实现 `validate()` 方法，以允许这些约束用于验证。

- 未记录的 `URLResolver._is_callback()`、`URLResolver._callback_strs` 和 `URLPattern.lookup_str()` 已被移动到 `django.contrib.admindocs.utils`。

- `Model.full_clean()` 方法现在将 `exclude` 值转换为一个 `set`。最好将 `exclude` 值作为一个 `set` 传递给 `Model.clean_fields()`、`Model.full_clean()`、`Model.validate_unique()` 和 `Model.validate_constraints()` 方法。

- `asgiref` 的最小支持版本从 3.4.1 提高到 3.5.2。

- 组合表达式不再在参数类型匹配时猜测 `output_field` 的不稳定行为。因此，解析数据库函数和组合表达式的 `output_field` 现在可能会在混合类型的情况下崩溃。在这种情况下，你需要明确设置 `output_field`。

- `makemessages` 命令在不需要更新时不再更改 `.po` 文件。在旧版本中，`POT-Creation-Date` 总是会被更新。

## 4.1 版本中弃用的功能

### 通过 GET 方式注销登录

Logging out via `GET` requests to the `built-in logout view` is deprecated. Use `POST` requests instead.

如果您想保留 HTML 链接的用户体验，可以使用一个被样式化为链接的表单：

    <form id="logout-form" method="post" action="{% url 'admin:logout' %}">
      {% csrf_token %}
      <button type="submit">{% translate "Log out" %}</button>
    </form>

    #logout-form {
      display: inline;
    }
    #logout-form button {
      background: none;
      border: none;
      cursor: pointer;
      padding: 0;
      text-decoration: underline;
    }

### 杂项

- 对于扁平化的 URL 列表的站点地图索引模板的上下文已被弃用。自定义站点地图索引模板应该根据调整后的 上下文变量 进行更新，期望一个具有 `location` 和可选 `lastmod` 属性的对象列表。

- `CSRF_COOKIE_MASKED` 过渡设置已移除。

- 在 Python 3.6 及更高版本中，`django.utils.functional.cached_property()` 的 `name` 参数已被弃用，因为它不再必要。

- `django.contrib.postgres.constraints.ExclusionConstraint` 的 `opclasses` 参数已被弃用，而应使用 `ExclusionConstraint.expressions` 中的 `OpClass()`。要使用它，你需要在 `INSTALLED_APPS` 中添加 `'django.contrib.postgres'`。

  在进行这些更改后，`makemigrations` 将生成一个新的迁移，其中包含两个操作：`RemoveConstraint` 和 `AddConstraint`。由于这些更改不影响数据库架构，可以使用 `SeparateDatabaseAndState` 操作来仅更新迁移状态而不运行任何 SQL。将生成的操作移动到 `SeparateDatabaseAndState` 的 `state_operations` 参数中。例如：

      class Migration(migrations.Migration):
          ...

          operations = [
              migrations.SeparateDatabaseAndState(
                  database_operations=[],
                  state_operations=[
                      migrations.RemoveConstraint(...),
                      migrations.AddConstraint(...),
                  ],
              ),
          ]

- 未记录的能够将 `errors=None` 传递给 `SimpleTestCase.assertFormError()` 和 `assertFormsetError()` 已被弃用。请改用 `errors=[]`。

- 由于存在远程代码执行的风险，`django.contrib.sessions.serializers.PickleSerializer` 已被弃用。

- 在没有提供 `chunk_size` 参数的情况下，对预取相关对象的查询集使用 `QuerySet.iterator()` 的用法已被弃用。在旧版本中，不会进行预取。提供 `chunk_size` 的值表示希望每个块所需的预取额外查询。

- 将未保存的模型实例传递给相关的过滤器已被弃用。在 Django 5.0 中，将引发异常。

- `RemoteUserBackend.configure_user()` 的签名中添加了 `created=True`。不接受此参数的 `RemoteUserBackend` 子类的支持已被弃用。

- 别名 `django.utils.timezone.utc` 到 `datetime.timezone.utc` 的使用已经被弃用。请直接使用 `datetime.timezone.utc`。

- 在 `SimpleTestCase.assertFormError()` 和 `assertFormsetError()` 中传递响应对象和表单/表单集名称已被弃用。请使用以下方式：

      assertFormError(response.context["form_name"], ...)
      assertFormsetError(response.context["formset_name"], ...)

  或者直接传递表单/表单集对象。

- 未记录的 `django.contrib.gis.admin.OpenLayersWidget` 模块已被弃用。

- `django.contrib.auth.hashers.CryptPasswordHasher` 已废弃。

- 在 `Expression.asc()` 和 `Expression.desc()` 方法以及 `OrderBy` 表达式中传递 `nulls_first=False` 或 `nulls_last=False` 的能力已被弃用。请改用 `None`。

- `"django/forms/default.html"` 和 `"django/forms/formsets/default.html"` 模板，它们是表格模板的代理，已被弃用。请使用具体的模板。

- 未记录的 `LogoutView.get_next_page()` 方法已被重命名为 `get_success_url()`。

## 在 4.1 版本中移除的功能

这些功能已经结束了其弃用周期，并在 Django 4.1 中被移除。

有关这些更改的详细信息，包括如何删除对这些功能的使用，请参阅 在 3.2 中被废弃的功能。

- 不再支持将不支持使用 `copy.deepcopy()` 创建深层副本的对象分配给 `TestCase.setUpTestData()` 中的类属性。

- 不再支持在 `BaseCommand.requires_system_checks` 中使用布尔值。

- `django.core.validators.EmailValidator` 的 `whitelist` 参数和 `domain_whitelist` 属性已被移除。

- `default_app_config` 应用程序配置变量已被移除。

- `TransactionTestCase.assertQuerysetEqual()` 在与字符串值进行比较时不再调用 `repr()` 方法来处理查询集。

- `django.core.cache.backends.memcached.MemcachedCache` 已被移除。

- 对 `django.contrib.messages.storage.cookie.CookieStorage` 使用的 Django 3.2 之前的消息格式的支持已被移除。