---
title: "Django 4.1 版本发行说明"
version: 5.2
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/5.2/releases/4.1/
canonical: https://djangodocs.dev/zh-hans/5.2/releases/4.1/
---
# Django 4.1 版本发行说明

*2022 年 8 月 3 日*

欢迎使用 Django 4.1！

这些发布说明涵盖了 [新功能](#whats-new-4-1)，以及从 Django 4.0 或更早版本升级时需要注意的一些 [不兼容变更](#backwards-incompatible-4-1)。我们已经 [开始了某些功能的弃用过程](#deprecated-features-4-1)。

如果你要更新现有的项目，请看 [如何将 Django 更新至新的版本](/zh-hans/5.2/howto/upgrade-version/) 指南。

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

请参阅 [异步类视图](/zh-hans/5.2/topics/class-based-views/#async-class-based-views) 以获取更多详细信息。

### 异步的 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 异步支持的发展。

请参阅 [异步查询](/zh-hans/5.2/topics/db/queries/#async-queries) 以获取详细信息和限制。

### 约束的验证

在 [`Meta.constraints`](/zh-hans/5.2/ref/models/options/#django.db.models.Options.constraints) 选项中定义的 [`Check`](/zh-hans/5.2/ref/models/constraints/#django.db.models.CheckConstraint)、[`unique`](/zh-hans/5.2/ref/models/constraints/#django.db.models.UniqueConstraint) 和 [`exclusion`](/zh-hans/5.2/ref/contrib/postgres/constraints/#django.contrib.postgres.constraints.ExclusionConstraint) 约束现在在 [模型验证](/zh-hans/5.2/ref/models/instances/#validating-objects) 期间进行检查。

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

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

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

为了方便采用新的输出样式，现在可以通过项目级别的 [`FORM_RENDERER`](/zh-hans/5.2/ref/settings/#std-setting-FORM_RENDERER) 设置来配置默认的表单和表单集模板。

请查看 [下面的表单部分](#forms-4-1) 以获取完整的详细信息。

### `CSRF_COOKIE_MASKED` 设置

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

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

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

### 次要特性

#### [`django.contrib.admin`](/zh-hans/5.2/ref/contrib/admin/#module-django.contrib.admin)

- 管理员 [深色模式 CSS 变量](/zh-hans/5.2/ref/contrib/admin/#admin-theming) 现在应用在一个单独的样式表和模板块中。
- 提供自定义 `FieldListFilter` 子类的 [ModelAdmin 列表过滤器](/zh-hans/5.2/ref/contrib/admin/filters/#modeladmin-list-filters) 现在可以在使用 `__in` 查询时控制查询字符串值的分隔符，用于多个值的过滤。
- 管理员的 [`history view`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.history_view) 现在支持分页。
- 相关的小部件包装现在有一个指向对象修改表单的链接。
- [`AdminSite.get_app_list()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.AdminSite.get_app_list) 方法现在允许更改管理员首页上应用程序和模型的顺序。

#### [`django.contrib.auth`](/zh-hans/5.2/topics/auth/#module-django.contrib.auth)

- PBKDF2 密码哈希器的默认迭代次数从 320 , 000 增加到 390 , 000 。
- [`RemoteUserBackend.configure_user()`](/zh-hans/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend.configure_user) 方法现在允许将用户属性与远程系统（如 LDAP 目录）中的属性同步。

#### [`django.contrib.gis`](/zh-hans/5.2/ref/contrib/gis/#module-django.contrib.gis)

- 新的 [`GEOSGeometry.make_valid()`](/zh-hans/5.2/ref/contrib/gis/geos/#django.contrib.gis.geos.GEOSGeometry.make_valid) 方法允许将无效的几何图形转换为有效的几何图形。
- [`GEOSGeometry.normalize()`](/zh-hans/5.2/ref/contrib/gis/geos/#django.contrib.gis.geos.GEOSGeometry.normalize) 的新参数 `clone` 允许创建几何图形的归一化克隆。

#### [`django.contrib.postgres`](/zh-hans/5.2/ref/contrib/postgres/#module-django.contrib.postgres)

- 新的 [`BitXor()`](/zh-hans/5.2/ref/contrib/postgres/aggregates/#django.contrib.postgres.aggregates.BitXor) 聚合函数返回所有非空输入值的按位 `XOR` 的 `int` 值。
- [`SpGistIndex`](/zh-hans/5.2/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.SpGistIndex) 现在在 PostgreSQL 14+ 上支持覆盖索引。
- [`ExclusionConstraint`](/zh-hans/5.2/ref/contrib/postgres/constraints/#django.contrib.postgres.constraints.ExclusionConstraint) 现在在 PostgreSQL 14+ 上支持使用 SP-GiST 索引的覆盖排除约束。
- 新的 [`DateTimeRangeField`](/zh-hans/5.2/ref/contrib/postgres/fields/#django.contrib.postgres.fields.DateTimeRangeField.default_bounds) 和 [`DecimalRangeField`](/zh-hans/5.2/ref/contrib/postgres/fields/#django.contrib.postgres.fields.DecimalRangeField.default_bounds) 的 `default_bounds` 属性允许为列表和元组输入指定边界。
- [`ExclusionConstraint`](/zh-hans/5.2/ref/contrib/postgres/constraints/#django.contrib.postgres.constraints.ExclusionConstraint) 现在允许使用 [`OpClass()`](/zh-hans/5.2/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.OpClass) 表达式指定操作符类。

#### [`django.contrib.sitemaps`](/zh-hans/5.2/ref/contrib/sitemaps/#module-django.contrib.sitemaps)

- 默认的站点地图索引模板 `<sitemapindex>` 现在在可用时包括 `<lastmod>` 时间戳，通过新的 [`get_latest_lastmod()`](/zh-hans/5.2/ref/contrib/sitemaps/#django.contrib.sitemaps.Sitemap.get_latest_lastmod) 方法。自定义站点地图索引模板应该根据调整后的 [上下文变量](/zh-hans/5.2/ref/contrib/sitemaps/#sitemap-index-context-variables) 进行更新。

#### [`django.contrib.staticfiles`](/zh-hans/5.2/ref/contrib/staticfiles/#module-django.contrib.staticfiles)

- [`ManifestStaticFilesStorage`](/zh-hans/5.2/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage) 现在会将 CSS 源映射引用的路径替换为它们的哈希版本。

#### 数据库后端

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

#### 表单

- 渲染表单时默认使用的模板，例如在模板中作为 `{{ form }}` 显示，现在可以在项目级别通过在提供给 [`FORM_RENDERER`](/zh-hans/5.2/ref/settings/#std-setting-FORM_RENDERER) 的类上设置 [`form_template_name`](/zh-hans/5.2/ref/forms/renderers/#django.forms.renderers.BaseRenderer.form_template_name) 来配置。

  [`Form.template_name`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.template_name) 现在是一个属性，延迟到渲染器，但可以用一个字符串值覆盖，以指定每个表单类的模板名称。

  同样，可以通过匹配的 [`formset_template_name`](/zh-hans/5.2/ref/forms/renderers/#django.forms.renderers.BaseRenderer.formset_template_name) 渲染器属性来指定用于渲染表单集的默认模板。
- 新的 `div.html` 表单模板引用了 [`Form.template_name_div`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.template_name_div) 属性，并与 [`Form.as_div()`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.as_div) 方法匹配，使用 HTML `<div>` 元素来渲染表单。

  推荐使用这种新的输出样式，而不是现有的 [`as_table()`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.as_table)、[`as_p()`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.as_p) 和 [`as_ul()`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.as_ul) 样式，因为模板实现了 `<fieldset>` 和 `<legend>` 来组合相关的输入，对屏幕阅读器用户更容易导航。

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

  您可以通过 [`FORM_RENDERER`](/zh-hans/5.2/ref/settings/#std-setting-FORM_RENDERER) 设置之一来应用其中之一。例如：

  ```
  FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
  ```

  一旦 `<div>` 输出样式成为默认样式（从 Django 5.0 开始），这些过渡渲染器将被弃用，并计划在 Django 6.0 中移除。届时可以删除 `FORM_RENDERER` 声明。
- 如果新的 `<div>` 输出样式不适用于您的项目，您应该定义一个渲染器子类，指定 [`form_template_name`](/zh-hans/5.2/ref/forms/renderers/#django.forms.renderers.BaseRenderer.form_template_name) 和 [`formset_template_name`](/zh-hans/5.2/ref/forms/renderers/#django.forms.renderers.BaseRenderer.formset_template_name) 以适应您所需的样式，并相应地设置 [`FORM_RENDERER`](/zh-hans/5.2/ref/settings/#std-setting-FORM_RENDERER)。

  例如，对于 [`as_p()`](/zh-hans/5.2/ref/forms/api/#django.forms.Form.as_p) 使用的 `<p>` 输出样式，您可以定义一个表单渲染器设置，将 `form_template_name` 设置为 `"django/forms/p.html"`，将 `formset_template_name` 设置为 `"django/forms/formsets/p.html"`。
- 新的 [`legend_tag()`](/zh-hans/5.2/ref/forms/api/#django.forms.BoundField.legend_tag) 允许通过 [`label_tag()`](/zh-hans/5.2/ref/forms/api/#django.forms.BoundField.label_tag) 的新 `tag` 参数以 `<legend>` 标签方式呈现字段标签。
- 对于 [`modelformset_factory()`](/zh-hans/5.2/ref/forms/models/#django.forms.models.modelformset_factory) 和 [`inlineformset_factory()`](/zh-hans/5.2/ref/forms/models/#django.forms.models.inlineformset_factory)，新的 `edit_only` 参数允许防止创建新对象。
- [媒体](/zh-hans/5.2/topics/forms/media/) 的 `js` 和 `css` 类属性现在允许使用可散列的对象，而不仅仅是路径字符串，只要这些对象实现了 `__html__()` 方法（通常在使用 [`html_safe()`](/zh-hans/5.2/ref/utils/#django.utils.html.html_safe) 装饰器时）。
- 新的 [`BoundField.use_fieldset`](/zh-hans/5.2/ref/forms/api/#django.forms.BoundField.use_fieldset) 和 [`Widget.use_fieldset`](/zh-hans/5.2/ref/forms/widgets/#django.forms.Widget.use_fieldset) 属性有助于识别那些应该在 `<fieldset>` 中与 `<legend>` 一起分组的小部件。
- [`BaseFormSet`](/zh-hans/5.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet) 的 [error\_messages](/zh-hans/5.2/topics/forms/formsets/#formsets-error-messages) 参数现在允许通过传递 `'too_few_forms'` 和 `'too_many_forms'` 键来自定义无效表单数量的错误消息。
- [`IntegerField`](/zh-hans/5.2/ref/forms/fields/#django.forms.IntegerField)、[`FloatField`](/zh-hans/5.2/ref/forms/fields/#django.forms.FloatField) 和 [`DecimalField`](/zh-hans/5.2/ref/forms/fields/#django.forms.DecimalField) 现在可以选择接受一个 `step_size` 参数。这用于设置 `step` HTML 属性，并在表单提交时进行验证。

#### 国际化

- [`i18n_patterns()`](/zh-hans/5.2/topics/i18n/translation/#django.conf.urls.i18n.i18n_patterns) 函数现在支持同时包含脚本和区域的语言。

#### 管理命令

- [`makemigrations --no-input`](/zh-hans/5.2/ref/django-admin/#cmdoption-makemigrations-noinput) 现在记录默认答案和无法创建迁移的原因。
- 新的 [`makemigrations --scriptable`](/zh-hans/5.2/ref/django-admin/#cmdoption-makemigrations-scriptable) 选项将日志输出和输入提示重定向到 `stderr`，仅将生成的迁移文件的路径写入 `stdout`。
- 新的 [`migrate --prune`](/zh-hans/5.2/ref/django-admin/#cmdoption-migrate-prune) 选项允许从 `django_migrations` 表中删除不存在的迁移。
- 由 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject)、[`startapp`](/zh-hans/5.2/ref/django-admin/#django-admin-startapp)、[`optimizemigration`](/zh-hans/5.2/ref/django-admin/#django-admin-optimizemigration)、[`makemigrations`](/zh-hans/5.2/ref/django-admin/#django-admin-makemigrations) 和 [`squashmigrations`](/zh-hans/5.2/ref/django-admin/#django-admin-squashmigrations) 创建的 Python 文件现在如果在您的 `PATH` 上存在 `black` 命令，将会使用它进行格式化。
- 新的 [`optimizemigration`](/zh-hans/5.2/ref/django-admin/#django-admin-optimizemigration) 命令允许优化迁移操作。

#### 迁移

- 新的 [`RenameIndex`](/zh-hans/5.2/ref/migration-operations/#django.db.migrations.operations.RenameIndex) 操作允许重命名在 [`Meta.indexes`](/zh-hans/5.2/ref/models/options/#django.db.models.Options.indexes) 或 `index_together` 选项中定义的索引。
- 迁移自动检测器现在在重命名 [`Meta.indexes`](/zh-hans/5.2/ref/models/options/#django.db.models.Options.indexes) 中定义的索引时，生成 [`RenameIndex`](/zh-hans/5.2/ref/migration-operations/#django.db.migrations.operations.RenameIndex) 操作，而不是 `RemoveIndex` 和 `AddIndex`。
- 迁移自动检测器现在会在将 `Meta.index_together` 中定义的索引移动到 [`Meta.indexes`](/zh-hans/5.2/ref/models/options/#django.db.models.Options.indexes) 时生成 [`RenameIndex`](/zh-hans/5.2/ref/migration-operations/#django.db.migrations.operations.RenameIndex) 操作，而不是 `AlterIndexTogether` 和 `AddIndex`。

#### 模型

- [`Window`](/zh-hans/5.2/ref/models/expressions/#django.db.models.expressions.Window) 表达式的 `order_by` 参数现在可以接受对字段和转换的字符串引用。
- 新的 [`CONN_HEALTH_CHECKS`](/zh-hans/5.2/ref/settings/#std-setting-CONN_HEALTH_CHECKS) 设置允许启用对 [持久数据库连接](/zh-hans/5.2/ref/databases/#persistent-database-connections) 进行健康检查，以减少失败的请求次数，例如在数据库服务器重新启动后。
- 现在，当插入一行时违反唯一约束时，[`QuerySet.bulk_create()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) 支持更新字段。这在 MariaDB、MySQL、PostgreSQL 和 SQLite 3.24+ 上都受支持。
- [`QuerySet.iterator()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.iterator) 现在支持在提供了 `chunk_size` 参数的情况下预取相关对象。在旧版本中，不进行预取。
- [`Q`](/zh-hans/5.2/ref/models/querysets/#django.db.models.Q) 对象和查询集现在可以使用 `^` 作为异或（`XOR`）运算符进行组合。`XOR` 在 MariaDB 和 MySQL 上有本地支持。对于不支持 `XOR` 的数据库，查询将被转换为使用 `AND`、`OR` 和 `NOT` 的等效查询。
- 新的 [Field.non\_db\_attrs](/zh-hans/5.2/howto/custom-model-fields/#custom-field-non-db-attrs) 属性允许自定义不影响列定义的字段属性。
- 在 PostgreSQL 上，`AutoField`、`BigAutoField` 和 `SmallAutoField` 现在作为标识列（identity columns）创建，而不是带有序列的序列列（serial columns）。

#### 请求和响应

- [`HttpResponse.set_cookie()`](/zh-hans/5.2/ref/request-response/#django.http.HttpResponse.set_cookie) 现在支持 [`timedelta`](https://docs.python.org/3/library/datetime.html#datetime.timedelta) 对象作为 `max_age` 参数。

#### 安全

- 新的 [`SECRET_KEY_FALLBACKS`](/zh-hans/5.2/ref/settings/#std-setting-SECRET_KEY_FALLBACKS) 设置允许提供一组值用于密钥轮换。
- [`SECURE_PROXY_SSL_HEADER`](/zh-hans/5.2/ref/settings/#std-setting-SECURE_PROXY_SSL_HEADER) 设置现在支持在头部值中以逗号分隔的协议列表。

#### 信号

- [`pre_delete`](/zh-hans/5.2/ref/signals/#django.db.models.signals.pre_delete) 和 [`post_delete`](/zh-hans/5.2/ref/signals/#django.db.models.signals.post_delete) 信号现在会分发删除的 `origin`。

#### 模板

- 在包装 [`json_script`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-json_script) 模板过滤器时，不再需要 HTML `<script>` 元素的 `id` 属性。
- 在开发环境中，当 [`DEBUG`](/zh-hans/5.2/ref/settings/#std-setting-DEBUG) 为 `True` 且未指定 [`OPTIONS['loaders']`](/zh-hans/5.2/ref/settings/#std-setting-TEMPLATES-OPTIONS) 时，现在会启用 [`cached template loader`](/zh-hans/5.2/ref/templates/api/#django.template.loaders.cached.Loader)。如果需要，您可以指定 `OPTIONS['loaders']` 来覆盖这个设置。

#### 测试

- [`DiscoverRunner`](/zh-hans/5.2/topics/testing/advanced/#django.test.runner.DiscoverRunner) 现在支持在 macOS、Windows 和任何默认 [`multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing) 启动方法为 `spawn` 的系统上并行运行测试。
- [`django.test.TestCase`](/zh-hans/5.2/topics/testing/tools/#django.test.TestCase) 中标记为持久的嵌套原子块现在会引发 `RuntimeError`，与测试外部相同。
- [`SimpleTestCase.assertFormError()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertFormError) 和 [`assertFormsetError()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertFormSetError) 现在支持直接传递表单/表单集对象。

#### URLs

- 新的 [`ResolverMatch.captured_kwargs`](/zh-hans/5.2/ref/urlresolvers/#django.urls.ResolverMatch.captured_kwargs) 属性存储了从 URL 解析的捕获的关键字参数。
- 新的 [`ResolverMatch.extra_kwargs`](/zh-hans/5.2/ref/urlresolvers/#django.urls.ResolverMatch.extra_kwargs) 属性存储了传递给视图函数的额外关键字参数。

#### 实用程序

- `SimpleLazyObject` 现在支持加法操作。
- [`mark_safe()`](/zh-hans/5.2/ref/utils/#django.utils.safestring.mark_safe) 现在保留懒惰对象。

#### 验证器

- 新的 [`StepValueValidator`](/zh-hans/5.2/ref/validators/#django.core.validators.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`](/zh-hans/5.2/ref/contrib/gis/#module-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 岁孩子的父母。

有关这种差异的更多讨论，请参阅 [跨多值关联](/zh-hans/5.2/topics/db/queries/#spanning-multi-valued-relationships) 主题。在 Django 4.0 及更早版本中，[`get_search_results()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_search_results) 遵循第二个示例查询，但这种未记录的行为导致了具有过多连接的查询。

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

为了统一与未保存的模型实例的多对多关系的行为，反向外键现在在调用未保存对象的 [`related managers`](/zh-hans/5.2/ref/models/relations/#django.db.models.fields.related.RelatedManager) 时会引发 `ValueError`。

### 杂项

- [`ForeignKey`](/zh-hans/5.2/ref/models/fields/#django.db.models.ForeignKey)、[`ManyToManyField`](/zh-hans/5.2/ref/models/fields/#django.db.models.ManyToManyField) 和 [`GenericRelation`](/zh-hans/5.2/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericRelation) 的相关管理器现在被缓存在它们所属的 [`Model`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model) 实例上。*这个变更在 Django 4.1.2 中被撤销了。*
- [`DiscoverRunner`](/zh-hans/5.2/topics/testing/advanced/#django.test.runner.DiscoverRunner) 现在会为标记为 [`unittest.expectedFailure()`](https://docs.python.org/3/library/unittest.html#unittest.expectedFailure) 的测试意外成功返回非零错误码。
- [`CsrfViewMiddleware`](/zh-hans/5.2/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware) 现在不再像在 DOM 中遮蔽 CSRF 令牌一样遮蔽 CSRF cookie。
- [`CsrfViewMiddleware`](/zh-hans/5.2/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware) 现在使用 `request.META['CSRF_COOKIE']` 来存储未遮蔽的 CSRF 密钥，而不是遮蔽版本。这是一个未记录的、私有的 API。
- [`ModelAdmin.actions`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.actions) 和 [`inlines`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines) 属性现在默认为空元组，而不是空列表，以防止意外的变更。
- 在 CSS [表单媒体](/zh-hans/5.2/topics/forms/media/) 的 `<link>` 标签中不再包含 `type="text/css"` 属性。
- `formset:added` 和 `formset:removed` JavaScript 事件现在是纯 JavaScript 事件，不依赖于 jQuery。有关此更改的更多详细信息，请参阅 [内联表单事件](/zh-hans/5.2/ref/contrib/admin/javascript/#admin-javascript-inline-form-events)。
- 未记录的 `django.utils.log.log_response()` 函数的 `exc_info` 参数已被替换为 `exception`。
- 未记录的 `django.views.static.was_modified_since()` 函数的 `size` 参数已被移除。
- 管理员注销界面现在使用 `POST` 请求。
- 未记录的 `InlineAdminFormSet.non_form_errors` 属性已被替换为 `non_form_errors()` 方法。这与 `BaseFormSet` 保持一致。
- 根据 [上面](#templates-4-1)，在开发中现在启用了缓存模板加载器。如果有必要，你可以指定 `OPTIONS['loaders']` 来覆盖这个设置。
- 未记录的 `django.contrib.auth.views.SuccessURLAllowedHostsMixin` 混合类已被替换为 `RedirectURLMixin`。
- [`BaseConstraint`](/zh-hans/5.2/ref/models/constraints/#django.db.models.BaseConstraint) 的子类必须实现 [`validate()`](/zh-hans/5.2/ref/models/constraints/#django.db.models.BaseConstraint.validate) 方法，以允许这些约束用于验证。
- 未记录的 `URLResolver._is_callback()`、`URLResolver._callback_strs` 和 `URLPattern.lookup_str()` 已被移动到 `django.contrib.admindocs.utils`。
- [`Model.full_clean()`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model.full_clean) 方法现在将 `exclude` 值转换为一个 `set`。最好将 `exclude` 值作为一个 `set` 传递给 [`Model.clean_fields()`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model.clean_fields)、[`Model.full_clean()`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model.full_clean)、[`Model.validate_unique()`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model.validate_unique) 和 [`Model.validate_constraints()`](/zh-hans/5.2/ref/models/instances/#django.db.models.Model.validate_constraints) 方法。
- `asgiref` 的最小支持版本从 3.4.1 提高到 3.5.2。
- 组合表达式不再在参数类型匹配时猜测 `output_field` 的不稳定行为。因此，解析数据库函数和组合表达式的 `output_field` 现在可能会在混合类型的情况下崩溃。在这种情况下，你需要明确设置 `output_field`。
- [`makemessages`](/zh-hans/5.2/ref/django-admin/#django-admin-makemessages) 命令在不需要更新时不再更改 `.po` 文件。在旧版本中，`POT-Creation-Date` 总是会被更新。

## 4.1 版本中弃用的功能

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

通过 `GET` 请求注销到 [`内置的注销视图`](/zh-hans/5.2/topics/auth/default/#django.contrib.auth.views.LogoutView) 已经不推荐使用。请改为使用 `POST` 请求。

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

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

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

### 杂项

- 对于扁平化的 URL 列表的站点地图索引模板的上下文已被弃用。自定义站点地图索引模板应该根据调整后的 [上下文变量](/zh-hans/5.2/ref/contrib/sitemaps/#sitemap-index-context-variables) 进行更新，期望一个具有 `location` 和可选 `lastmod` 属性的对象列表。
- `CSRF_COOKIE_MASKED` 过渡设置已移除。
- 在 Python 3.6 及更高版本中，[`django.utils.functional.cached_property()`](/zh-hans/5.2/ref/utils/#django.utils.functional.cached_property) 的 `name` 参数已被弃用，因为它不再必要。
- `django.contrib.postgres.constraints.ExclusionConstraint` 的 `opclasses` 参数已被弃用，而应使用 [`ExclusionConstraint.expressions`](/zh-hans/5.2/ref/contrib/postgres/constraints/#django.contrib.postgres.constraints.ExclusionConstraint.expressions) 中的 [`OpClass()`](/zh-hans/5.2/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.OpClass)。要使用它，你需要在 [`INSTALLED_APPS`](/zh-hans/5.2/ref/settings/#std-setting-INSTALLED_APPS) 中添加 `'django.contrib.postgres'`。

  在进行这些更改后，[`makemigrations`](/zh-hans/5.2/ref/django-admin/#django-admin-makemigrations) 将生成一个新的迁移，其中包含两个操作：`RemoveConstraint` 和 `AddConstraint`。由于这些更改不影响数据库架构，可以使用 [`SeparateDatabaseAndState`](/zh-hans/5.2/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState) 操作来仅更新迁移状态而不运行任何 SQL。将生成的操作移动到 [`SeparateDatabaseAndState`](/zh-hans/5.2/ref/migration-operations/#django.db.migrations.operations.SeparateDatabaseAndState) 的 `state_operations` 参数中。例如：

  ```
  class Migration(migrations.Migration):
      ...

      operations = [
          migrations.SeparateDatabaseAndState(
              database_operations=[],
              state_operations=[
                  migrations.RemoveConstraint(...),
                  migrations.AddConstraint(...),
              ],
          ),
      ]
  ```
- 未记录的能够将 `errors=None` 传递给 [`SimpleTestCase.assertFormError()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertFormError) 和 [`assertFormsetError()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertFormSetError) 已被弃用。请改用 `errors=[]`。
- 由于存在远程代码执行的风险，`django.contrib.sessions.serializers.PickleSerializer` 已被弃用。
- 在没有提供 `chunk_size` 参数的情况下，对预取相关对象的查询集使用 `QuerySet.iterator()` 的用法已被弃用。在旧版本中，不会进行预取。提供 `chunk_size` 的值表示希望每个块所需的预取额外查询。
- 将未保存的模型实例传递给相关的过滤器已被弃用。在 Django 5.0 中，将引发异常。
- [`RemoteUserBackend.configure_user()`](/zh-hans/5.2/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend.configure_user) 的签名中添加了 `created=True`。不接受此参数的 `RemoteUserBackend` 子类的支持已被弃用。
- 别名 `django.utils.timezone.utc` 到 [`datetime.timezone.utc`](https://docs.python.org/3/library/datetime.html#datetime.timezone.utc) 的使用已经被弃用。请直接使用 [`datetime.timezone.utc`](https://docs.python.org/3/library/datetime.html#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 中被废弃的功能](/zh-hans/5.2/releases/3.2/#deprecated-features-3-2)。

- 不再支持将不支持使用 `copy.deepcopy()` 创建深层副本的对象分配给 `TestCase.setUpTestData()` 中的类属性。
- 不再支持在 [`BaseCommand.requires_system_checks`](/zh-hans/5.2/howto/custom-management-commands/#django.core.management.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 之前的消息格式的支持已被移除。
