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

*2021 年 12 月 7 日*

欢迎使用 Django 4.0 ！

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

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

## Python 兼容性

Django 4.0 支持 Python 3.8、3.9 和 3.10。我们 **强烈建议** 并只官方支持每个系列的最新版本。

Django 3.2.x 系列是最后一个支持 Python 3.6 和 3.7 的版本。

## Django 4.0 新特性

### `zoneinfo` 默认时区实现

Python 标准库的 [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo) 现在是 Django 中默认的时区实现。

这是从使用 `pytz` 到使用 [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo) 迁移的下一步。Django 3.2 允许使用非 `pytz` 时区。Django 4.0 将 `zoneinfo` 作为默认实现。对于 `pytz` 的支持现在已经不推荐使用，并将在 Django 5.0 中移除。

[`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html#module-zoneinfo) 是自 Python 3.9 起的 Python 标准库的一部分。如果你正在使用 Python 3.8，那么 `backports.zoneinfo` 包会在安装 Django 时自动安装。

迁移到 `zoneinfo` 应该在很大程度上是透明的。选择当前时区、在表单和模板中将日期时间实例转换为当前时区，以及在 UTC 中进行的带时区日期时间的操作都不受影响。

然而，如果你正在使用非 UTC 时区，并使用 `pytz` 的 `normalize()` 和 `localize()` API，可能还涉及到 [`TIME_ZONE`](/zh-hans/4.2/ref/settings/#std-setting-DATABASE-TIME_ZONE) 设置，那么你需要审查你的代码，因为\`\`pytz\`\` 和 `zoneinfo` 并不完全等同。

为了给这样的审核留出时间，过渡性的 [`USE_DEPRECATED_PYTZ`](/zh-hans/4.2/ref/settings/#std-setting-USE_DEPRECATED_PYTZ) 设置允许在 4.x 发布周期内继续使用 `pytz`。这个设置将在 Django 5.0 中移除。

此外，`zoneinfo` 的作者创建了一个名为 [pytz\_deprecation\_shim](https://pytz-deprecation-shim.readthedocs.io/en/latest/index.html) 的包，可用于协助从 `pytz` 迁移。这个包提供了帮助你安全移除 `pytz` 的 shims，并有一个详细的 [迁移指南](https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html)，展示了如何切换到新的 `zoneinfo` API。

如果你需要一个渐进的更新路径，建议使用 [pytz\_deprecation\_shim](https://pytz-deprecation-shim.readthedocs.io/en/latest/index.html) 和 [`USE_DEPRECATED_PYTZ`](/zh-hans/4.2/ref/settings/#std-setting-USE_DEPRECATED_PYTZ) 过渡性设置。

### 函数式唯一约束

[`UniqueConstraint()`](/zh-hans/4.2/ref/models/constraints/#django.db.models.UniqueConstraint) 的新的 [`*expressions`](/zh-hans/4.2/ref/models/constraints/#django.db.models.UniqueConstraint.expressions) 位置参数允许在表达式和数据库函数上创建功能性的唯一约束。例如：

```
from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower

class MyModel(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)

    class Meta:
        constraints = [
            UniqueConstraint(
                Lower("first_name"),
                Lower("last_name").desc(),
                name="first_last_name_unique",
            ),
        ]
```

功能性唯一约束是通过在模型中使用 [`Meta.constraints`](/zh-hans/4.2/ref/models/options/#django.db.models.Options.constraints) 选项来添加的。

### `scrypt` 密码哈希器

新的 [scrypt 密码哈希器](/zh-hans/4.2/topics/auth/passwords/#scrypt-usage) 更安全，推荐使用，但它不是默认选项，因为它需要 OpenSSL 1.1+ 和更多内存。

### Redis 缓存后端

新的 `django.core.cache.backends.redis.RedisCache` 缓存后端提供了内置的支持，用于使用 Redis 进行缓存。需要 [redis-py](https://pypi.org/project/redis/) 的版本为 3.0.0 或更高。更多详情请参阅 Django 中关于使用 Redis 进行缓存的 [文档](/zh-hans/4.2/topics/cache/#redis)。

### 基于模板的表单渲染

[`Forms`](/zh-hans/4.2/ref/forms/api/#django.forms.Form)、[Formsets](/zh-hans/4.2/topics/forms/formsets/) 和 [`ErrorList`](/zh-hans/4.2/ref/forms/api/#django.forms.ErrorList) 现在使用模板引擎进行渲染，以增强自定义功能。查看 `Form` 的新方法 [`render()`](/zh-hans/4.2/ref/forms/api/#django.forms.Form.render)、[`get_context()`](/zh-hans/4.2/ref/forms/api/#django.forms.Form.get_context) 和 [`template_name`](/zh-hans/4.2/ref/forms/api/#django.forms.Form.template_name)，以及关于 `Formset` 的 [formset 渲染](/zh-hans/4.2/topics/forms/formsets/#formset-rendering)。

### 次要特性

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

- `admin/base.html` 模板现在有一个新的块 `header`，其中包含了管理站点的标题。
- 新的 [`ModelAdmin.get_formset_kwargs()`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_formset_kwargs) 方法允许自定义传递给表单集构造函数的关键字参数。
- 导航侧边栏现在有一个快速筛选工具栏。
- 新的上下文变量 `model` 包含了每个模型的模型类，已添加到 [`AdminSite.each_context()`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.AdminSite.each_context) 方法中。
- 新的 [`ModelAdmin.search_help_text`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_help_text) 属性允许指定搜索框的描述性文本。
- [`InlineModelAdmin.verbose_name_plural`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.verbose_name_plural) 属性现在会回退到 [`InlineModelAdmin.verbose_name`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.verbose_name) \+ `'s'`。
- jQuery 从版本 3.5.1 升级到 3.6.0 。

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

- admindocs 现在允许复杂的设置，其中 [`ROOT_URLCONF`](/zh-hans/4.2/ref/settings/#std-setting-ROOT_URLCONF) 不是一个字符串。
- `admindocs` 的模型部分现在显示缓存的属性。

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

- PBKDF2 密码哈希器的默认迭代次数从 260 , 000 增加到 320 , 000 。
- 新的 [`LoginView.next_page`](/zh-hans/4.2/topics/auth/default/#django.contrib.auth.views.LoginView.next_page) 属性和 [`get_default_redirect_url()`](/zh-hans/4.2/topics/auth/default/#django.contrib.auth.views.LoginView.get_default_redirect_url) 方法允许自定义登录后的重定向。

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

- 新增对 SpatiaLite 5 的支持。
- [`GDALRaster`](/zh-hans/4.2/ref/contrib/gis/gdal/#django.contrib.gis.gdal.GDALRaster) 现在允许在任何 GDAL 虚拟文件系统中创建栅格数据。
- 新的 [`GISModelAdmin`](/zh-hans/4.2/ref/contrib/gis/admin/#django.contrib.gis.admin.GISModelAdmin) 类允许自定义用于 `GeometryField` 的小部件，这是鼓励使用的，而不是不推荐使用的 `GeoModelAdmin` 和 `OSMGeoAdmin`。

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

- PostgreSQL 后端现在支持通过服务名称进行连接。更多详情请参阅 [PostgreSQL 连接配置](/zh-hans/4.2/ref/databases/#postgresql-connection-settings)。
- 新的 [`AddConstraintNotValid`](/zh-hans/4.2/ref/contrib/postgres/operations/#django.contrib.postgres.operations.AddConstraintNotValid) 操作允许在 PostgreSQL 上创建检查约束，而无需验证所有现有行是否满足新约束。
- 新的 [`ValidateConstraint`](/zh-hans/4.2/ref/contrib/postgres/operations/#django.contrib.postgres.operations.ValidateConstraint) 操作允许验证在 PostgreSQL 上使用 [`AddConstraintNotValid`](/zh-hans/4.2/ref/contrib/postgres/operations/#django.contrib.postgres.operations.AddConstraintNotValid) 创建的检查约束。
- 新的 [`ArraySubquery()`](/zh-hans/4.2/ref/contrib/postgres/expressions/#django.contrib.postgres.expressions.ArraySubquery) 表达式允许在 PostgreSQL 上使用子查询来构建值列表。
- 新的 [`trigram_word_similar`](/zh-hans/4.2/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_word_similar) 查找以及 [`TrigramWordDistance()`](/zh-hans/4.2/ref/contrib/postgres/search/#django.contrib.postgres.search.TrigramWordDistance) 和 [`TrigramWordSimilarity()`](/zh-hans/4.2/ref/contrib/postgres/search/#django.contrib.postgres.search.TrigramWordSimilarity) 表达式允许使用 trigram 单词相似度。

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

- [`ManifestStaticFilesStorage`](/zh-hans/4.2/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage) 现在会将 JavaScript 源映射引用的路径替换为它们的哈希版本。
- [`ManifestFilesMixin`](/zh-hans/4.2/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestFilesMixin) 和 [`ManifestStaticFilesStorage`](/zh-hans/4.2/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage) 的新参数 `manifest_storage` 允许自定义清单文件的存储。

#### 缓存

- `django.core.cache.backends.base.BaseCache` 的新异步 API 开始了使缓存后端支持异步的过程。新的异步方法都有 `a` 前缀的名称，例如 `aadd()`、`aget()`、`aset()`、`aget_or_set()` 或 `adelete_many()`。

  今后，`a` 前缀将用于一般方法的异步变体。

#### CSRF

- CSRF 保护现在会查看是否存在 `Origin` 标头。为了实现这一点，需要对 [`CSRF_TRUSTED_ORIGINS`](/zh-hans/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS) 设置进行 [一些更改](#csrf-trusted-origins-changes-4-0)。

#### 表单

- [`ModelChoiceField`](/zh-hans/4.2/ref/forms/fields/#django.forms.ModelChoiceField) 现在会在引发 `invalid_choice` 错误消息的 [`ValidationError`](/zh-hans/4.2/ref/exceptions/#django.core.exceptions.ValidationError) 中的 `params` 参数中包含提供的值，这允许自定义错误消息使用 `%(value)s` 占位符。
- [`BaseFormSet`](/zh-hans/4.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet) 现在会在渲染非表单错误时添加一个额外的类 `nonform`，以帮助区分它们与特定于表单的错误。
- [`BaseFormSet`](/zh-hans/4.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet) 现在允许通过设置 [`deletion_widget`](/zh-hans/4.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet.deletion_widget) 属性或覆盖 [`get_deletion_widget()`](/zh-hans/4.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet.get_deletion_widget) 方法来自定义在通过 [`can_delete`](/zh-hans/4.2/topics/forms/formsets/#django.forms.formsets.BaseFormSet.can_delete) 删除表单时使用的小部件。

#### 国际化

- 添加了对马来语的支持和翻译。

#### 通用视图

- [`DeleteView`](/zh-hans/4.2/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView) 现在使用 [`FormMixin`](/zh-hans/4.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin)，允许你提供一个 [`Form`](/zh-hans/4.2/ref/forms/api/#django.forms.Form) 的子类，例如带有复选框的表单，来确认删除。此外，这还允许 `DeleteView` 与 [`django.contrib.messages.views.SuccessMessageMixin`](/zh-hans/4.2/ref/contrib/messages/#django.contrib.messages.views.SuccessMessageMixin) 配合使用。

  根据 `FormMixin`，对于 POST 请求的对象删除是在 `form_valid()` 中处理的。如果需要，应将 `delete()` 处理程序中的自定义删除逻辑移动到 `form_valid()` 或共享的辅助方法中。

#### 日志

- 现在，用于 SQL 调用的数据库的别名会作为额外的上下文与每条消息一起传递到 [django.db.backends](/zh-hans/4.2/ref/logging/#django-db-logger) 记录器中。

#### 管理命令

- [`runserver`](/zh-hans/4.2/ref/django-admin/#django-admin-runserver) 管理命令现在支持 [`--skip-checks`](/zh-hans/4.2/ref/django-admin/#cmdoption-skip-checks) 选项。
- 在 PostgreSQL 上，[`dbshell`](/zh-hans/4.2/ref/django-admin/#django-admin-dbshell) 现在支持指定密码文件。
- [`shell`](/zh-hans/4.2/ref/django-admin/#django-admin-shell) 命令现在在启动时会尊重 [`sys.__interactivehook__`](https://docs.python.org/3/library/sys.html#sys.__interactivehook__)。这允许在交互式会话之间加载 shell 历史记录。因此，在 *隔离* 模式下运行时不再加载 `readline`。
- 新的 [`BaseCommand.suppressed_base_arguments`](/zh-hans/4.2/howto/custom-management-commands/#django.core.management.BaseCommand.suppressed_base_arguments) 属性允许在帮助输出中抑制不支持的默认命令选项。
- 新的 [`startapp --exclude`](/zh-hans/4.2/ref/django-admin/#cmdoption-startapp-exclude) 和 [`startproject --exclude`](/zh-hans/4.2/ref/django-admin/#cmdoption-startproject-exclude) 选项允许从模板中排除目录。

#### 模型

- 新的 [`QuerySet.contains(obj)`](/zh-hans/4.2/ref/models/querysets/#django.db.models.query.QuerySet.contains) 方法返回查询集是否包含给定对象。它尝试以最简单和最快的方式执行查询。
- [`Round()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.Round) 数据库函数的新 `precision` 参数允许指定舍入后的小数位数。
- 使用 SQLite 3.35+ 时，[`QuerySet.bulk_create()`](/zh-hans/4.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) 现在会为对象设置主键。
- [`DurationField`](/zh-hans/4.2/ref/models/fields/#django.db.models.DurationField) 现在在 SQLite 上支持乘法和除法以及标量值。
- [`QuerySet.bulk_update()`](/zh-hans/4.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update) 现在会返回更新的对象数量。
- 新的 [`Expression.empty_result_set_value`](/zh-hans/4.2/ref/models/expressions/#django.db.models.Expression.empty_result_set_value) 属性允许在函数用于空结果集时指定要返回的值。
- 在 MariaDB 10.6+ 上，现在允许使用 [`QuerySet.select_for_update()`](/zh-hans/4.2/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update) 的 `skip_locked` 参数。
- [`Lookup`](/zh-hans/4.2/ref/models/lookups/#django.db.models.Lookup) 表达式现在可以在 `QuerySet` 的注释、聚合和直接筛选中使用。
- 内置聚合函数的新 [default](/zh-hans/4.2/ref/models/querysets/#aggregate-default) 参数允许指定当查询集（或分组）不包含条目时要返回的值，而不是返回 `None`。

#### 请求和响应

- [`SecurityMiddleware`](/zh-hans/4.2/ref/middleware/#django.middleware.security.SecurityMiddleware) 现在会添加具有值 `'same-origin'` 的 [Cross-Origin Opener Policy](/zh-hans/4.2/ref/middleware/#cross-origin-opener-policy) 头，以防止跨源弹出窗口共享相同的浏览上下文。你可以通过将 [`SECURE_CROSS_ORIGIN_OPENER_POLICY`](/zh-hans/4.2/ref/settings/#std-setting-SECURE_CROSS_ORIGIN_OPENER_POLICY) 设置为 `None` 来阻止添加此头部。

#### 信号

- [`pre_migrate()`](/zh-hans/4.2/ref/signals/#django.db.models.signals.pre_migrate) 和 [`post_migrate()`](/zh-hans/4.2/ref/signals/#django.db.models.signals.post_migrate) 信号现在有一个新的 `stdout` 参数，允许将输出重定向到类似流的对象。在发出详细输出时，应优先考虑使用它，以便在测试时能够正确捕获输出，而不是使用 [`sys.stdout`](https://docs.python.org/3/library/sys.html#sys.stdout) 和 [`print()`](https://docs.python.org/3/library/functions.html#print)。

#### 模板

- 模板过滤器 [`floatformat`](/zh-hans/4.2/ref/templates/builtins/#std-templatefilter-floatformat) 现在允许使用 `u` 后缀来强制禁用本地化。

#### 测试

- [`django.test.utils.setup_databases()`](/zh-hans/4.2/topics/testing/advanced/#django.test.utils.setup_databases) 的新参数 `serialized_aliases` 决定了哪些 [`DATABASES`](/zh-hans/4.2/ref/settings/#std-setting-DATABASES) 别名的测试数据库应该被序列化以允许使用 [serialized\_rollback](/zh-hans/4.2/topics/testing/overview/#test-case-serialized-rollback) 特性。
- Django 测试运行器现在在并行测试中支持 [`--buffer`](/zh-hans/4.2/ref/django-admin/#cmdoption-test-buffer) 选项。
- [`DiscoverRunner`](/zh-hans/4.2/topics/testing/advanced/#django.test.runner.DiscoverRunner) 的新参数 `logger` 允许使用 Python [logger](https://docs.python.org/3/library/logging.html#logger) 进行日志记录。
- 新的 [`DiscoverRunner.log()`](/zh-hans/4.2/topics/testing/advanced/#django.test.runner.DiscoverRunner.log) 方法提供了一种记录消息的方式，它使用 `DiscoverRunner.logger` 进行日志记录，如果未设置则打印到控制台。
- Django 测试运行器现在支持 [`--shuffle`](/zh-hans/4.2/ref/django-admin/#cmdoption-test-shuffle) 选项，以随机顺序执行测试。
- [`test --parallel`](/zh-hans/4.2/ref/django-admin/#cmdoption-test-parallel) 选项现在支持值 `auto`，以为每个处理器核心运行一个测试进程。
- [`TestCase.captureOnCommitCallbacks()`](/zh-hans/4.2/topics/testing/tools/#django.test.TestCase.captureOnCommitCallbacks) 现在会捕获在执行 [`transaction.on_commit()`](/zh-hans/4.2/topics/db/transactions/#django.db.transaction.on_commit) 回调期间添加的新回调。

## 4.0 版本中不向后兼容的变更

### 数据库后端 API

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

- `DatabaseOperations.year_lookup_bounds_for_date_field()` 和 `year_lookup_bounds_for_datetime_field()` 方法现在接受可选的 `iso_year` 参数，以支持 ISO-8601 周编号年份的范围。
- `DatabaseSchemaEditor._unique_sql()` 和 `_create_unique_sql()` 方法的第二个参数现在是 `fields`，而不再是 `columns`。

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

- 移除了对 PostGIS 2.3 的支持。
- 移除了对 GDAL 2.0 和 GEOS 3.5 的支持。

### 停止支持 PostgreSQL 9.6

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

此外，`psycopg2` 的最低支持版本已从 2.5.4 提高到 2.8.4，因为 `psycopg2` 2.8.4 是第一个支持 Python 3.8 的版本。

### 停止支持 Oracle 12.2 和 18c

Oracle 12.2 的上游支持将于 2022 年 3 月结束，Oracle 18c 的上游支持将于 2021 年 6 月结束。 Django 3.2 将得到支持直至 2024 年 4 月。 Django 4.0 正式支持 Oracle 19c 。

### `CSRF_TRUSTED_ORIGINS` 变更

#### 格式变更

在 [`CSRF_TRUSTED_ORIGINS`](/zh-hans/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS) 设置中，值必须包括方案（例如，`'http://'` 或 `'https://'`），而不仅仅是主机名。

此外，以点开头的值现在必须在点之前加上一个星号。例如，将 `'.example.com'` 更改为 `'https://*.example.com'`。

系统检查会检测到任何所需的更改。

#### 现在可能需要配置它

由于 CSRF 保护现在参考 `Origin` 标头，如果你通过将 [`CSRF_COOKIE_DOMAIN`](/zh-hans/4.2/ref/settings/#std-setting-CSRF_COOKIE_DOMAIN) （或者如果启用了 [`CSRF_USE_SESSIONS`](/zh-hans/4.2/ref/settings/#std-setting-CSRF_USE_SESSIONS)，则为 [`SESSION_COOKIE_DOMAIN`](/zh-hans/4.2/ref/settings/#std-setting-SESSION_COOKIE_DOMAIN)）设置为以点开头的值以允许来自子域的请求，你可能需要设置 [`CSRF_TRUSTED_ORIGINS`](/zh-hans/4.2/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS)。

### `SecurityMiddleware` 不再设置 `X-XSS-Protection` 头

如果 `SECURE_BROWSER_XSS_FILTER` 设置为 `True`，则 [`SecurityMiddleware`](/zh-hans/4.2/ref/middleware/#django.middleware.security.SecurityMiddleware) 不再设置 `X-XSS-Protection` 头。此设置已被移除。

大多数现代浏览器不再支持 `X-XSS-Protection` HTTP 头。你可以使用 [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy) 来代替，但请不要允许 `'unsafe-inline'` 脚本。

如果您想要支持旧版浏览器并设置标头，请在自定义中间件中使用以下代码行：

```
response.headers.setdefault("X-XSS-Protection", "1; mode=block")
```

### 迁移自动检测器的更改

迁移自动检测器现在使用模型状态而不是模型类。此外，对于 `ForeignKey` 和 `ManyToManyField` 字段的迁移操作不再指定未在字段初始化期间传递的属性。

作为副作用，在某些情况下，运行 `makemigrations` 可能会为 `ManyToManyField` 和 `ForeignKey` 字段生成无操作的 `AlterField` 操作。

### `DeleteView` 变更

[`DeleteView`](/zh-hans/4.2/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView) 现在使用 [`FormMixin`](/zh-hans/4.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin) 来处理 POST 请求。因此，任何在 `delete()` 处理程序中的自定义删除逻辑应该移动到 `form_valid()`，或者如果需要的话，可以移动到共享的辅助方法。

### Oracle 上的表和列命名方案发生了变化。

Django 4.0 无意中更改了 Oracle 上的表和列命名方案。这会导致模型和字段的名称超过 30 个字符的错误。不幸的是，需要重命名一些 Oracle 表和列。请使用 [33789](https://code.djangoproject.com/ticket/33789#comment:15) 中的升级脚本生成 `RENAME` 语句来更改命名方案。

### 杂项

- 已移除对 `cx_Oracle` 版本低于 7.0 的支持。
- 为了允许在子路径上提供 Django 站点而不更改 [`STATIC_URL`](/zh-hans/4.2/ref/settings/#std-setting-STATIC_URL) 的值，现在在默认的 [`startproject`](/zh-hans/4.2/ref/django-admin/#django-admin-startproject) 模板中从该设置中移除了前导斜杠（现在是 `'static/'`）。
- 当直接访问 [`AdminSite`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.AdminSite) 的管理 `index` 视图时，不再使用 `never_cache` 进行装饰，而是建议通过 `AdminSite.urls` 属性或 `AdminSite.get_urls()` 方法访问。
- 对切片的查询集执行不支持的操作现在会引发 `TypeError` 而不是 `AssertionError`。
- 未记录的 `django.test.runner.reorder_suite()` 函数已更名为 `reorder_tests()`。现在它接受一个测试的可迭代对象而不是测试套件，并返回一个测试的迭代器。
- 现在，如果使用空的 `name` 调用 `FileSystemStorage.delete()`，会引发 `ValueError` 而不是 `AssertionError`。
- 如果使用无效的 `content` 或 `mimetype` 参数调用 `EmailMultiAlternatives.attach_alternative()` 或 `EmailMessage.attach()`，现在会引发 `ValueError` 而不是 `AssertionError`。
- [`assertHTMLEqual()`](/zh-hans/4.2/topics/testing/tools/#django.test.SimpleTestCase.assertHTMLEqual) 不再将没有值的非布尔属性视为与具有相同名称和值的属性相等。
- 现在，无法加载的测试，例如由于语法错误等原因，使用 [`test --tag`](/zh-hans/4.2/ref/django-admin/#cmdoption-test-tag) 时始终匹配。
- 未记录的 `django.contrib.admin.utils.lookup_needs_distinct()` 函数已更名为 `lookup_spawns_duplicates()`。
- 未记录的 `HttpRequest.get_raw_uri()` 方法已被移除。 [`HttpRequest.build_absolute_uri()`](/zh-hans/4.2/ref/request-response/#django.http.HttpRequest.build_absolute_uri) 方法可能是一个合适的替代方法。
- 未记录的 `ModelAdmin.log_addition()`、`log_change()` 和 `log_deletion()` 方法的 `object` 参数已更名为 `obj`。
- [`RssFeed`](/zh-hans/4.2/ref/utils/#django.utils.feedgenerator.RssFeed)、[`Atom1Feed`](/zh-hans/4.2/ref/utils/#django.utils.feedgenerator.Atom1Feed) 及其子类现在将没有内容的元素作为自关闭标签进行输出。
- `NodeList.render()` 不再将单个节点的 `render()` 方法的输出转换为字符串。根据文档，`Node.render()` 应始终返回一个字符串。
- `django.db.models.sql.query.Query` 的 `where_class` 属性以及 `ForeignObject` 和 `ForeignObjectRel` 的私有方法 `get_extra_restriction()` 的 `where_class` 参数已被移除。如果需要，可以初始化 `django.db.models.sql.where.WhereNode`。
- 未记录的 `Query.add_filter()` 方法的 `filter_clause` 参数被替换为两个位置参数 `filter_lhs` 和 `filter_rhs`。
- [`CsrfViewMiddleware`](/zh-hans/4.2/ref/middleware/#django.middleware.csrf.CsrfViewMiddleware) 现在使用 `request.META['CSRF_COOKIE_NEEDS_UPDATE']` 代替 `request.META['CSRF_COOKIE_USED']`、`request.csrf_cookie_needs_reset` 和 `response.csrf_cookie_set` 来跟踪 CSRF cookie 是否应该发送。这是一个未记录的私有 API。
- 未记录的 `TRANSLATOR_COMMENT_MARK` 常量已从 `django.template.base` 移动到 `django.utils.translation.template`。
- 未记录的 `django.db.migrations.state.ProjectState.__init__()` 方法的 `real_apps` 参数现在必须是一个集合（set），如果提供的话。
- [`RadioSelect`](/zh-hans/4.2/ref/forms/widgets/#django.forms.RadioSelect) 和 [`CheckboxSelectMultiple`](/zh-hans/4.2/ref/forms/widgets/#django.forms.CheckboxSelectMultiple) 小部件现在在 `<div>` 标签中呈现，以便屏幕阅读器更简洁地宣读它们。如果需要以前的行为，请使用来自 Django 3.2 的适当模板 [覆盖小部件模板](/zh-hans/4.2/ref/forms/renderers/#overriding-built-in-widget-templates)。
- 模板过滤器 [`floatformat`](/zh-hans/4.2/ref/templates/builtins/#std-templatefilter-floatformat) 不再依赖于 `USE_L10N` 设置，并始终返回本地化的输出。使用 `u` 后缀来禁用本地化。
- `USE_L10N` 设置的默认值已更改为 `True`。有关更多详细信息，请参阅上面的 [本地化部分](#use-l10n-deprecation)。
- 作为 [迁移到 zoneinfo](#whats-new-4-0) 的一部分，[`django.utils.timezone.utc`](/zh-hans/4.2/ref/utils/#django.utils.timezone.utc) 被更改为别名 [`datetime.timezone.utc`](https://docs.python.org/3/library/datetime.html#datetime.timezone.utc)。
- `asgiref` 的最低支持版本已从 3.3.2 增加到 3.4.1。

## 在 4.0 版本中废弃的功能

### 使用 `pytz` 时区

作为 [迁移到 zoneinfo](#whats-new-4-0) 的一部分，不推荐使用 `pytz` 时区。

相应地，以下函数的 `is_dst` 参数也已被弃用：

- [`django.db.models.query.QuerySet.datetimes()`](/zh-hans/4.2/ref/models/querysets/#django.db.models.query.QuerySet.datetimes)
- [`django.db.models.functions.Trunc()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.Trunc)
- [`django.db.models.functions.TruncSecond()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncSecond)
- [`django.db.models.functions.TruncMinute()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncMinute)
- [`django.db.models.functions.TruncHour()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncHour)
- [`django.db.models.functions.TruncDay()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncDay)
- [`django.db.models.functions.TruncWeek()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncWeek)
- [`django.db.models.functions.TruncMonth()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncMonth)
- [`django.db.models.functions.TruncQuarter()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncQuarter)
- [`django.db.models.functions.TruncYear()`](/zh-hans/4.2/ref/models/database-functions/#django.db.models.functions.TruncYear)
- [`django.utils.timezone.make_aware()`](/zh-hans/4.2/ref/utils/#django.utils.timezone.make_aware)

在 Django 5.0 中将移除对 `pytz` 的支持。

### 时区支持

为了遵循良好的实践，[`USE_TZ`](/zh-hans/4.2/ref/settings/#std-setting-USE_TZ) 设置的默认值将从 `False` 更改为 `True`，并且在 Django 5.0 中将默认启用时区支持。

请注意，由 [`django-admin startproject`](/zh-hans/4.2/ref/django-admin/#django-admin-startproject) 创建的默认 `settings.py` 文件自 Django 1.4 起就包括 [`USE_TZ = True`](/zh-hans/4.2/ref/settings/#std-setting-USE_TZ)。

你可以在那之前在项目设置中将 `USE_TZ` 设置为 `False` 以选择不使用时区支持。

### 本地化

为了遵循良好的实践，`USE_L10N` 设置的默认值从 `False` 更改为 `True`。

此外，从此版本开始，`USE_L10N` 已被弃用。从 Django 5.0 开始，默认情况下，Django 显示的任何日期或数字都将进行本地化。

Django 仍将支持 [`{% localize %}`](/zh-hans/4.2/topics/i18n/formatting/#std-templatetag-localize) 标签以及 [`localize`](/zh-hans/4.2/topics/i18n/formatting/#std-templatefilter-localize)/ [`unlocalize`](/zh-hans/4.2/topics/i18n/formatting/#std-templatefilter-unlocalize) 过滤器。

### 杂项

- `SERIALIZE` 测试设置已被弃用，因为可以从启用 [serialized\_rollback](/zh-hans/4.2/topics/testing/overview/#test-case-serialized-rollback) 选项的 [`databases`](/zh-hans/4.2/topics/testing/tools/#django.test.TestCase.databases) 推断出。
- 未记录的 `django.utils.baseconv` 模块已被弃用。
- 未记录的 `django.utils.datetime_safe` 模块已被弃用。
- 在 Django 5.0 中，构建在请求上下文之外的站点地图的默认协议将从 `'http'` 更改为 `'https'`。
- [`DiscoverRunner.build_suite()`](/zh-hans/4.2/topics/testing/advanced/#django.test.runner.DiscoverRunner.build_suite) 和 [`DiscoverRunner.run_tests()`](/zh-hans/4.2/topics/testing/advanced/#django.test.runner.DiscoverRunner.run_tests) 的 `extra_tests` 参数已被弃用。
- 在 Django 5.0 中，当没有行时，[`ArrayAgg`](/zh-hans/4.2/ref/contrib/postgres/aggregates/#django.contrib.postgres.aggregates.ArrayAgg)、[`JSONBAgg`](/zh-hans/4.2/ref/contrib/postgres/aggregates/#django.contrib.postgres.aggregates.JSONBAgg) 和 [`StringAgg`](/zh-hans/4.2/ref/contrib/postgres/aggregates/#django.contrib.postgres.aggregates.StringAgg) 聚合将返回 `None`，而不是分别返回 `[]`、`[]` 和 `''`。如果需要以前的行为，请显式将 `default` 设置为 `Value([])`、`Value('[]')` 或 `Value('')`。
- `django.contrib.gis.admin.GeoModelAdmin` 和 `OSMGeoAdmin` 类已被弃用。请改为使用 [`ModelAdmin`](/zh-hans/4.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin) 和 [`GISModelAdmin`](/zh-hans/4.2/ref/contrib/gis/admin/#django.contrib.gis.admin.GISModelAdmin)。
- 由于表单渲染现在使用模板引擎，未记录的 `BaseForm._html_output()` 辅助方法已被弃用。
- 从 `ErrorList` 和 `ErrorDict` 返回 `str` 的能力已被弃用。预期这些方法返回一个 `SafeString`。

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

这些功能已经完成了废弃周期，并在 Django 4.0 中被移除。

请参阅 [在 3.0 中被废弃的功能](/zh-hans/4.2/releases/3.0/#deprecated-features-3-0) 以获取有关这些更改的详细信息，包括如何删除对这些功能的使用。

- `django.utils.http.urlquote()`, `urlquote_plus()`, `urlunquote()`, 和 `urlunquote_plus()` 已被移除。
- `django.utils.encoding.force_text()` 和 `smart_text()` 已被移除。
- `django.utils.translation.ugettext()`, `ugettext_lazy()`, `ugettext_noop()`, `ungettext()`, 和 `ungettext_lazy()` 已被移除。
- `django.views.i18n.set_language()` 不会在 `request.session` 中设置用户语言（键为 `_language`）。
- `alias=None` 在 `django.db.models.Expression.get_group_by_cols()` 子类的签名中是必需的。
- `django.utils.text.unescape_entities()` 已被移除。
- `django.utils.http.is_safe_url()` 已被移除。

请参阅 [在 3.1 中被废弃的功能](/zh-hans/4.2/releases/3.1/#deprecated-features-3-1) 以获取有关这些更改的详细信息，包括如何删除对这些功能的使用。

- `PASSWORD_RESET_TIMEOUT_DAYS` 设置已被移除。
- [`isnull`](/zh-hans/4.2/ref/models/querysets/#std-fieldlookup-isnull) 查询不再允许使用非布尔值作为右侧的值。
- `django.db.models.query_utils.InvalidQuery` 异常类已被移除。
- `django-admin.py` 入口点已被移除。
- `HttpRequest.is_ajax()` 方法已被移除。
- 已移除对由 `django.contrib.messages.storage.cookie.CookieStorage` 使用的 Django 3.1 之前版本的 cookie 值编码格式的支持。
- 移除了对使用 SHA-1 哈希算法的 Django 3.1 之前版本密码重置令牌在管理站点的支持。
- 移除了对使用 Django 3.1 之前编码格式的会话的支持。
- 已移除对 Django 3.1 之前版本中使用 SHA-1 算法编码的 `django.core.signing.Signer` 签名的支持。
- 已移除在 `django.core.signing.loads()` 中对 Django 3.1 之前版本中使用 SHA-1 算法编码的 `django.core.signing.dumps()` 签名的支持。
- 移除了对使用 SHA-1 算法的 Django 3.1 之前用户会话的支持。
- `django.utils.deprecation.MiddlewareMixin.__init__()` 的 `get_response` 参数是必需的，并且不接受 `None`。
- `django.dispatch.Signal` 的 `providing_args` 参数已被移除。
- `django.utils.crypto.get_random_string()` 的 `length` 参数是必需的。
- `ModelMultipleChoiceField` 的 `list` 消息已被移除。
- 不再支持将原始列别名传递给 `QuerySet.order_by()`。
- `NullBooleanField` 模型字段已被移除，除了在历史迁移中的支持。
- `django.conf.urls.url()` 已被移除。
- `django.contrib.postgres.fields.JSONField` 模型字段已被移除，除了在历史迁移中的支持。
- `django.contrib.postgres.fields.jsonb.KeyTransform` 和 `django.contrib.postgres.fields.jsonb.KeyTextTransform` 已被移除。
- `django.contrib.postgres.forms.JSONField` 已被移除。
- `{% ifequal %}` 和 `{% ifnotequal %}` 模板标签已被移除。
- `DEFAULT_HASHING_ALGORITHM` 过渡设置已被移除。
