# Django 5.2.8 documentation

# Django 4.2 版本发行说明

2023 年 4 月 3 日

欢迎使用 Django 4.2 ！

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

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

Django 4.2 被指定为 长期支持版本。它将在发布后至少三年内接收安全更新。对于之前的 LTS 版本 Django 3.2，支持将在 2024 年 4 月结束。

## Python 兼容性

Django 4.2 支持 Python 3.8、3.9、3.10、3.11 和 3.12（截止到 4.2.8 版本）。我们 强烈推荐 并且只官方支持每个系列的最新版本。

## Django 4.2 新特性

### Psycopg 3 支持

Django 现在支持 psycopg 版本 3.1.8 或更高版本。要更新您的代码，请安装 psycopg library，您不需要更改 `ENGINE`，因为 `django.db.backends.postgresql` 支持这两个库。

对 `psycopg2` 的支持可能会在将来的某个时候被弃用并移除。

请注意，`psycopg` 3 对 `psycopg2` 进行了一些不兼容的更改。因此，您可能需要进行一些更改以适应与 psycopg2 的不同之处。

### 对列和表的注释

新的 `Field.db_comment` 和 `Meta.db_table_comment` 选项允许分别在列和表上创建注释。例如：

    from django.db import models

    class Question(models.Model):
        text = models.TextField(db_comment="Poll question")
        pub_date = models.DateTimeField(
            db_comment="Date and time when the question was published",
        )

        class Meta:
            db_table_comment = "Poll questions"

    class Answer(models.Model):
        question = models.ForeignKey(
            Question,
            on_delete=models.CASCADE,
            db_comment="Reference to a question",
        )
        answer = models.TextField(db_comment="Question answer")

        class Meta:
            db_table_comment = "Question answers"

此外，新的 `AlterModelTableComment` 操作允许更改在 `Meta.db_table_comment` 中定义的表注释。

### 对 BREACH 攻击的缓解措施

`GZipMiddleware` 现在包括对 BREACH 攻击的缓解措施。它将在 gzip 响应中添加最多 100 个随机字节，以增加 BREACH 攻击的难度。在 Heal The Breach (HTB) paper 中详细了解有关缓解技术。

### 内存中的文件存储

新的 `django.core.files.storage.InMemoryStorage` 类提供了非持久性存储，对于加速测试并避免磁盘访问非常有用。

### 自定义文件存储

新的 `STORAGES` 设置允许配置多个自定义文件存储后端。它还控制了管理 文件 （`"default"` 键）和 静态文件 （`"staticfiles"` 键）的存储引擎。

在此版本中，旧的 `DEFAULT_FILE_STORAGE` 和 `STATICFILES_STORAGE` 设置已被弃用。

### 次要特性

#### `django.contrib.admin`

- 现在可以在用户界面中切换管理界面的明亮或暗色主题，并且还可以设置为跟随系统设置。

- 管理界面现在更倾向于使用系统 UI 字体，不再需要下载字体。此外，提供了 CSS 变量，以便更轻松地覆盖默认字体系列。

- admin/delete_confirmation.html 模板现在具有一些额外的块和脚本钩子，以便于定制。

- `filter_horizontal` 和 `filter_vertical` 组件的选择选项现在是可过滤的。

- 模板 `admin/base.html` 现在具有一个新的块 `nav-breadcrumbs`，其中包含导航标志和 `breadcrumbs` 块。

- `ModelAdmin.list_editable` 现在在进行编辑时使用原子事务。

- jQuery 的版本已从 3.6.0 升级到 3.6.4 。

#### `django.contrib.auth`

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

- `UserCreationForm` 现在保存了自定义用户模型的多对多表单字段。

- 新的 `BaseUserCreationForm` 现在是自定义用户创建表单的推荐基类。

#### `django.contrib.gis`

- GeoJSON 序列化程序 现在输出序列化要素的 `id` 键，默认为对象的主键。

- `GDALRaster` 类现在支持 `pathlib.Path`。

- `GeoIP2` 类现在支持从 DB-IP 下载的 `.mmdb` 文件。

- OpenLayers 模板小部件不再包含内联 CSS（也删除了以前的 `map_css` 块），以更好地符合严格的内容安全策略。

- `OpenLayersWidget` 现在基于 OpenLayers 7.2.2（之前是 4.6.5）。

- 新的 `isempty` 查找和 `IsEmpty()` 表达式允许在 PostGIS 上筛选空几何图形。

- 新的 `FromWKB()` 和 `FromWKT()` 函数允许从 Well-known binary (WKB) 和 Well-known text (WKT) 表示中创建几何图形。

#### `django.contrib.postgres`

- 新的 `trigram_strict_word_similar` 查找以及 `TrigramStrictWordSimilarity()` 和 `TrigramStrictWordDistance()` 表达式允许使用 trigram 严格单词相似性。

- `arrayfield.overlap` 查找现在支持 `QuerySet.values()` 和 `values_list()` 作为右侧。

#### `django.contrib.sitemaps`

- 新的 `Sitemap.get_languages_for_item()` 方法允许自定义显示项目的语言列表。

#### `django.contrib.staticfiles`

- `ManifestStaticFilesStorage` 现在具有实验性支持，在 `import` 和 `export` 语句中用其哈希值替换 JavaScript 模块的路径。如果你想尝试它，可以子类化 `ManifestStaticFilesStorage` 并将 `support_js_module_import_aggregation` 属性设置为 `True`。

- 新的 `ManifestStaticFilesStorage.manifest_hash` 属性提供了对清单中所有文件的哈希，并在其中任何文件更改时更改。

#### 数据库后端

- 在 PostgreSQL 的 `OPTIONS` 中现在支持新的 `"assume_role"` 选项，允许指定 会话角色。

- 在 PostgreSQL 上，使用 `psycopg` 3.1.8+，现在支持 `OPTIONS` 中的新选项 `"server_side_binding"`，允许使用 服务器端绑定游标。

#### 错误报告

- 在 Python 3.11+ 上，调试页面现在显示 异常说明 和 细粒度错误位置。

- 会话 cookie 现在被视为凭据，因此在错误报告中被隐藏并替换为星号（`**********`）。

#### 表单

- `ModelForm` 现在接受新的 `Meta` 选项 `formfield_callback`，以自定义表单字段。

- `modelform_factory()` 现在尊重表单的 `Meta` 中的 `formfield_callback` 属性。

#### 国际化

- 增加了对中央库尔德语（索拉尼方言）的支持和翻译。

#### 日志

- django.db.backends 记录器现在以 `DEBUG` 级别记录事务管理查询（`BEGIN`、`COMMIT` 和 `ROLLBACK`）。

#### 管理命令

- `makemessages` 命令现在支持具有私有子标记的区域设置，例如 `nl_NL-x-informal`。

- 新的 `makemigrations --update` 选项将模型更改合并到最新的迁移中，并优化生成的操作。

#### 迁移

- 迁移现在支持对 `enum.Flag` 对象的序列化。

#### 模型

- `QuerySet` 现在在除执行聚合时的窗口函数的析取过滤查询外，广泛支持与 窗口函数 进行过滤。

- `prefetch_related()` 现在支持带有切片查询集的 `Prefetch` 对象。

- 现在支持在 `Field` 实例上 注册查找。

- 新的 `robust` 参数用于 `on_commit()`，允许在数据库事务成功提交后执行可能失败的操作。

- 新的 `KT()` 表达式表示 `JSONField` 的键、索引或路径转换的文本值。

- `Now` 现在在 MySQL 上支持微秒精度，在 SQLite 上支持毫秒精度。

- `F()` 表达式输出的 `BooleanField` 现在可以使用 `~F()` （取反操作符）进行取反。

- `Model` 现在提供了一些使用数据库的方法的异步版本，使用 `a` 前缀：`adelete()`、`arefresh_from_db()` 和 `asave()`。

- Related 管理器现在提供了一些更改相关对象集合的异步方法，使用 `a` 前缀：`aadd()`、`aclear()`、`aremove()` 和 `aset()`。

- `CharField.max_length` 不再需要在 PostgreSQL 上设置，因为它支持无限长度的 `VARCHAR` 列。

#### 请求和响应

- `StreamingHttpResponse` 现在在通过 ASGI 提供服务时支持异步迭代器。

#### 测试

- `test --debug-sql` 选项现在使用 `sqlparse` 格式化 SQL 查询。

- `RequestFactory`、`AsyncRequestFactory`、`Client` 和 `AsyncClient` 类现在支持 `headers` 参数，它接受一个包含头部名称和值的字典。这允许更自然的语法来声明头部。

      # Before:
      self.client.get("/home/", HTTP_ACCEPT_LANGUAGE="fr")
      await self.async_client.get("/home/", ACCEPT_LANGUAGE="fr")

      # After:
      self.client.get("/home/", headers={"accept-language": "fr"})
      await self.async_client.get("/home/", headers={"accept-language": "fr"})

#### 实用程序

- `django.utils.html.json_script()` 函数的新参数 `encoder` 允许自定义 JSON 编码器类。

- 私有的内部 vendored 版本的 `urllib.parse.urlsplit()` 现在会删除 `'\r'`、`'\n'` 和 `'\t'` （参见 CVE 2022-0391 和 bpo-43882）。这是为了保护可能错误使用内部 `url_has_allowed_host_and_scheme()` 函数而不是使用文档中记录的处理 URL 重定向的函数的项目。Django 的函数没有受到影响。

- 新的 `django.utils.http.content_disposition_header()` 函数返回根据 RFC 6266 规定的 `Content-Disposition` HTTP 标头值。

#### 验证器

- `CommonPasswordValidator` 使用的常见密码列表已更新为最新版本。

## Django 4.2 中的不向后兼容的变更

### 数据库后端 API

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

- `DatabaseFeatures.allows_group_by_pk` 已被移除，因为它仅保留以适应一个已被 MySQL 5.7.15 中正确的功能依赖检测所取代的 MySQL 扩展。请注意，仍然支持 `DatabaseFeatures.allows_group_by_selected_pks`，如果您的后端支持 `GROUP BY` 子句中的功能依赖检测，应该启用它，如 `SQL:1999` 标准所规定的。

- `inspectdb` 现在使用 `DatabaseIntrospection.get_table_description()` 中的 `display_size`，而不是 `internal_size` 用于 `CharField`。

### 不再支持 MariaDB 10.3

MariaDB 10.3 的上游支持将于 2023 年 5 月结束。 Django 4.2 支持 MariaDB 10.4 及更高版本。

### 不再支持 MySQL 5.7

MySQL 5.7 的上游支持将于 2023 年 10 月结束。 Django 4.2 支持 MySQL 8 及更高版本。

### 不再支持 PostgreSQL 11

PostgreSQL 11 的上游支持将于 2023 年 11 月结束。 Django 4.2 支持 PostgreSQL 12 及更高版本。

### 在 `Model.save()` 中设置 `update_fields` 可能现在是必需的

为了避免更新不必要的列，`QuerySet.update_or_create()` 现在将 `update_fields` 传递给 `Model.save()` 调用。因此，在调用 `super()` 之前，应该将在自定义的 `save()` 方法中修改的任何字段添加到 `update_fields` 关键字参数中。详细信息请参阅 重写之前定义的模型方法。

### 在 MySQL 上取消了对原始聚合的支持

MySQL 8+ 允许在 `GROUP BY` 列上使用函数依赖，因此在 Django 4.2 之前的版本中通过对主表的主键进行分组的解决方法已被移除。因此，在 MySQL 上不再支持使用 `RawSQL()` 进行聚合，因为无法确定这些聚合是否在 `GROUP BY` 子句中需要或有效。请改用 聚合函数。

### 杂项

- 未记录的 `django.http.multipartparser.parse_header()` 函数已被移除。请改用 `django.utils.http.parse_header_parameters()`。

- `{% blocktranslate asvar … %}` 的结果现在被标记为适用于（HTML）输出目的的安全内容。

- 在管理界面的搜索框中移除了 `autofocus` HTML 属性，因为它对屏幕阅读器可能会造成困惑。

- `makemigrations --check` 选项不再创建缺失的迁移文件。

- `Expression.get_group_by_cols()` 的 `alias` 参数已被移除。

- `sqlparse` 的最低支持版本已从 0.2.2 增加到 0.3.1。

- `Exists` 表达式的未记录的 `negated` 参数已被移除。

- 未记录的 `Query.add_annotation()` 方法的 `is_summary` 参数已被移除。

- 最低支持的 SQLite 版本从 3.9.0 提高到 3.21.0 。

- `asgiref` 的最低支持版本已从 3.5.2 增加到 3.6.0。

- `UserCreationForm` 现在拒绝仅在大小写上不同的用户名。如果需要之前的行为，请改用 `BaseUserCreationForm`。

- `mysqlclient` 的最低支持版本从 1.4.0 增加到 1.4.3。

- `argon2-cffi` 的最低支持版本已从 19.1.0 增加到 19.2.0。

- `Pillow` 的最低支持版本已从 6.2.0 增加到 6.2.1。

- `jinja2` 的最低支持版本已从 2.9.2 增加到 2.11.0。

- redis-py 的最低支持版本已从 3.0.0 增加到 3.4.0。

- 手动实例化的 `WSGIRequest` 对象必须为 `wsgi.input` 提供一个类似文件的对象。之前，Django 对于 WSGI 规范中指定的预期行为更加宽松。

- 已移除对 `PROJ` 版本低于 5 的支持。

- `EmailBackend` now verifies a `hostname` and `certificates`. If you need the previous behavior that is less restrictive and not recommended, subclass `EmailBackend` and override the `ssl_context` property.

## 在 4.2 版本中弃用的功能

### `index_together` 选项已被弃用，推荐使用 `indexes`

`Meta.index_together` 选项已被弃用，推荐使用 `indexes` 选项。

迁移现有的 `index_together` 应该作为一个迁移来处理。例如：

    class Author(models.Model):
        rank = models.IntegerField()
        name = models.CharField(max_length=30)

        class Meta:
            index_together = [["rank", "name"]]

应该变成：

    class Author(models.Model):
        rank = models.IntegerField()
        name = models.CharField(max_length=30)

        class Meta:
            indexes = [models.Index(fields=["rank", "name"])]

运行 `makemigrations` 命令将生成一个迁移，其中包含一个 `RenameIndex` 操作，用于重命名现有的索引。接下来，考虑合并迁移以从历史迁移中移除 `index_together`。

`AlterIndexTogether` 迁移操作现在官方上仅支持用于 Django 4.2 之前的迁移文件。出于向后兼容性的原因，它仍然是公共 API 的一部分，没有计划弃用或移除它，但不应该在新的迁移中使用。应该使用 `AddIndex` 和 `RemoveIndex` 操作代替。

### 传递编码的 JSON 字符串文字给 `JSONField` 已被弃用

`JSONField` 及其相关的查找和聚合操作曾允许传递 JSON 编码的字符串文字，这导致了在数据库后端的角度上对字符串文字是否已经编码的歧义。

在弃用期间，将尝试对字符串字面值进行 JSON 解码，并在成功时发出警告，指出应传递非编码形式的内容。

曾经用于传递 JSON 编码的字符串文字的代码：

    Document.objects.bulk_create(
        Document(data=Value("null")),
        Document(data=Value("[]")),
        Document(data=Value('"foo-bar"')),
    )
    Document.objects.annotate(
        JSONBAgg("field", default=Value("[]")),
    )

应该变成：

    Document.objects.bulk_create(
        Document(data=Value(None, JSONField())),
        Document(data=[]),
        Document(data="foo-bar"),
    )
    Document.objects.annotate(
        JSONBAgg("field", default=[]),
    )

从 Django 5.1+ 开始，字符串字面值将被隐式解释为 JSON 字符串字面值。

### 杂项

- The `BaseUserManager.make_random_password()` method is deprecated. See recipes and best practices for using Python's `secrets` module to generate passwords.

- `length_is` 模板过滤器已被弃用，推荐使用 `length` 和在 `{% if %}` 标签内使用 `==` 运算符。例如：

      {% if value|length == 4 %}…{% endif %}
      {% if value|length == 4 %}True{% else %}False{% endif %}

  而不是：

      {% if value|length_is:4 %}…{% endif %}
      {{ value|length_is:4 }}

- `django.contrib.auth.hashers.SHA1PasswordHasher`、`django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher` 和 `django.contrib.auth.hashers.UnsaltedMD5PasswordHasher` 已被弃用。

- `django.contrib.postgres.fields.CICharField` 已被弃用，推荐使用 `CharField(db_collation="…")`，并指定一个不区分大小写的非确定性排序规则(collation)。

- `django.contrib.postgres.fields.CIEmailField` 已被弃用，推荐使用 `EmailField(db_collation="…")`，并指定一个不区分大小写的非确定性排序规则(collation)。

- `django.contrib.postgres.fields.CITextField` 已被弃用，推荐使用 `TextField(db_collation="…")`，并指定一个不区分大小写的非确定性排序规则(collation)。

- `django.contrib.postgres.fields.CIText` mixin 已被弃用。

- `BaseGeometryWidget` 的 `map_height` 和 `map_width` 属性已被弃用，请改用 CSS 来设置地图小部件的大小。

- `SimpleTestCase.assertFormsetError()` 已被弃用，推荐使用 `assertFormSetError()`。

- `TransactionTestCase.assertQuerysetEqual()` 已被弃用，推荐使用 `assertQuerySetEqual()`。

- 将位置参数传递给 `Signer` 和 `TimestampSigner` 已被弃用，推荐使用仅限关键字的参数。

- `DEFAULT_FILE_STORAGE` 设置已被弃用，推荐使用 `STORAGES["default"]`。

- `STATICFILES_STORAGE` 设置已被弃用，推荐使用 `STORAGES["staticfiles"]`。

- `django.core.files.storage.get_storage_class()` 函数已被弃用。