# Django 5.2.8 documentation

# Django 5.0 版本发行说明

2023 年 12 月 4 日

欢迎使用 Django 5.0 ！

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

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

## Python 兼容性

Django 5.0 支持 Python 3.10、3.11 和 3.12。我们 强烈推荐 并且只官方支持每个系列的最新发布版本。

Django 4.2.x 系列是最后一个支持 Python 3.8 和 3.9 的版本。

## 对于较旧版本的 Django 的第三方库支持

在 Django 5.0 发布之后，我们建议第三方应用程序的作者停止对 4.2 之前的所有 Django 版本的支持。在那时，你应该能够使用 `python -Wd` 运行你包的测试，以便出现弃用警告。在进行弃用警告修复后，你的应用程序应该与 Django 5.0 兼容。

## Django 5.0 新特性

### 管理界面中的分面过滤器

在管理界面的 changelist 中，当通过 UI 切换开启时，现在会显示已应用过滤器的分面计数。此行为可以通过新的 `ModelAdmin.show_facets` 属性进行更改。更多信息请参阅 Facets。

### 简化的表单字段渲染模板

Django 5.0 引入了字段组（field group）的概念，以及字段组模板。这简化了渲染 Django 表单字段的相关元素，如标签、小部件、帮助文本和错误。

例如，下面的模板：

    <form>
    ...
    <div>
      {{ form.name.label_tag }}
      {% if form.name.help_text %}
        <div class="helptext" id="{{ form.name.auto_id }}_helptext">
          {{ form.name.help_text|safe }}
        </div>
      {% endif %}
      {{ form.name.errors }}
      {{ form.name }}
      <div class="row">
        <div class="col">
          {{ form.email.label_tag }}
          {% if form.email.help_text %}
            <div class="helptext" id="{{ form.email.auto_id }}_helptext">
              {{ form.email.help_text|safe }}
            </div>
          {% endif %}
          {{ form.email.errors }}
          {{ form.email }}
        </div>
        <div class="col">
          {{ form.password.label_tag }}
          {% if form.password.help_text %}
            <div class="helptext" id="{{ form.password.auto_id }}_helptext">
              {{ form.password.help_text|safe }}
            </div>
          {% endif %}
          {{ form.password.errors }}
          {{ form.password }}
        </div>
      </div>
    </div>
    ...
    </form>

现在可以简化为：

    <form>
    ...
    <div>
      {{ form.name.as_field_group }}
      <div class="row">
        <div class="col">{{ form.email.as_field_group }}</div>
        <div class="col">{{ form.password.as_field_group }}</div>
      </div>
    </div>
    ...
    </form>

`as_field_group()` 默认使用 `"django/forms/field.html"` 模板来渲染字段，并可以在每个项目、每个字段或每个请求的基础上进行自定义。请参阅 可重用的字段组模板。

### 数据库计算的默认值

新的 `Field.db_default` 参数设置了一个数据库计算的默认值。例如：

    from django.db import models
    from django.db.models.functions import Now, Pi

    class MyModel(models.Model):
        age = models.IntegerField(db_default=18)
        created = models.DateTimeField(db_default=Now())
        circumference = models.FloatField(db_default=2 * Pi())

### 数据库生成的模型字段

新的 `GeneratedField` 允许创建数据库生成的列。此字段可用于所有支持的数据库后端，以创建一个始终从其他字段计算得到的字段。例如：

    from django.db import models
    from django.db.models import F

    class Square(models.Model):
        side = models.IntegerField()
        area = models.GeneratedField(
            expression=F("side") * F("side"),
            output_field=models.BigIntegerField(),
            db_persist=True,
        )

### 声明字段选择项的更多选项

`Field.choices` （用于模型字段）和 `ChoiceField.choices` （用于表单字段）在声明它们的值时提供了更多的灵活性。在以前的 Django 版本中，`choices` 应该是一个包含 2 元组的列表，或者是一个 枚举类型 的子类，但后者需要访问 `.choices` 属性以提供预期形式的值：

    from django.db import models

    Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")

    SPORT_CHOICES = [
        ("Martial Arts", [("judo", "Judo"), ("karate", "Karate")]),
        ("Racket", [("badminton", "Badminton"), ("tennis", "Tennis")]),
        ("unknown", "Unknown"),
    ]

    class Winner(models.Model):
        name = models.CharField(...)
        medal = models.CharField(..., choices=Medal.choices)
        sport = models.CharField(..., choices=SPORT_CHOICES)

Django 5.0 添加了对接受映射或可调用对象的支持，而不是可迭代对象，并且不再需要直接使用 `.choices` 来扩展 枚举类型：

    from django.db import models

    Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")

    SPORT_CHOICES = {  # Using a mapping instead of a list of 2-tuples.
        "Martial Arts": {"judo": "Judo", "karate": "Karate"},
        "Racket": {"badminton": "Badminton", "tennis": "Tennis"},
        "unknown": "Unknown",
    }

    def get_scores():
        return [(i, str(i)) for i in range(10)]

    class Winner(models.Model):
        name = models.CharField(...)
        medal = models.CharField(..., choices=Medal)  # Using `.choices` not required.
        sport = models.CharField(..., choices=SPORT_CHOICES)
        score = models.IntegerField(choices=get_scores)  # A callable is allowed.

在内部，每当更新 `choices` 值时，提供的 `choices` 将被规范化为包含 2 元组的列表，作为规范形式。有关更多信息，请查看 模型字段参考中的 choices。

### 次要特性

#### `django.contrib.admin`

- 新的 `AdminSite.get_log_entries()` 方法允许自定义站点列出的日志条目的查询集。

- `django.contrib.admin.AllValuesFieldListFilter`、`ChoicesFieldListFilter`、`RelatedFieldListFilter` 和 `RelatedOnlyFieldListFilter` 管理筛选器现在处理多值查询参数。

- `XRegExp` 升级到版本 5.1.1，从之前的版本 3.2.0。

- 新的 `AdminSite.get_model_admin()` 方法返回给定模型类的管理类。

- `ModelAdmin.list_display` 中的属性现在支持 `boolean` 属性。

- jQuery 升级到版本 3.7.1，从之前的版本 3.6.4。

#### `django.contrib.auth`

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

- 现在提供了新的异步函数，使用 `a` 前缀：`django.contrib.auth.aauthenticate()`、`aget_user()`、`alogin()`、`alogout()` 和 `aupdate_session_auth_hash()`。

- `AuthenticationMiddleware` 现在添加了一个 `HttpRequest.auser()` 异步方法，用于返回当前已登录的用户。

- 新的 `django.contrib.auth.hashers.acheck_password()` 异步函数和 `AbstractBaseUser.acheck_password()` 方法允许异步检查用户密码。

#### `django.contrib.contenttypes`

- `QuerySet.prefetch_related()` 现在支持在结果集中存在非同质的情况下预取 `GenericForeignKey`。

#### `django.contrib.gis`

- 新的 `ClosestPoint()` 函数返回几何图形上距离另一个几何图形最近的二维点。

- GIS 聚合函数 现在支持 `filter` 参数。

- 添加了对 GDAL 3.7 和 GEOS 3.12 的支持。

- 新的 `GEOSGeometry.equals_identical()` 方法允许逐点等价检查几何图形。

#### `django.contrib.messages`

- 新的 `MessagesTestMixin.assertMessages()` 断言方法允许测试添加到 `response` 的 `messages`。

#### `django.contrib.postgres`

- `ExclusionConstraint` 的新属性 `violation_error_code` 允许在 模型验证 期间自定义 `ValidationError` 引发的 `code`。

#### 异步视图

- 在 ASGI 下，现在可以处理 `http.disconnect` 事件。这允许视图在客户端在生成响应之前断开连接时执行任何必要的清理工作。有关更多详细信息，请参阅 处理断开连接。

#### 装饰器

- 以下装饰器现在支持包装异步视图函数：

  - `cache_control()`

  - `never_cache()`

  - `no_append_slash()`

  - `csrf_exempt()`

  - `csrf_protect()`

  - `ensure_csrf_cookie()`

  - `requires_csrf_token()`

  - `sensitive_variables()`

  - `sensitive_post_parameters()`

  - `gzip_page()`

  - `condition()`

  - `conditional_page()`

  - `etag()`

  - `last_modified()`

  - `require_http_methods()`

  - `require_GET()`

  - `require_POST()`

  - `require_safe()`

  - `vary_on_cookie()`

  - `vary_on_headers()`

  - `xframe_options_deny()`

  - `xframe_options_sameorigin()`

  - `xframe_options_exempt()`

#### 错误报告

- `sensitive_variables()` 和 `sensitive_post_parameters()` 现在可以与异步函数一起使用。

#### 文件存储

- `File.open()` 现在将所有位置参数（`*args`）和关键字参数（`**kwargs`）传递给 Python 内置的 `open()`。

#### 表单

- 新的 `assume_scheme` 参数用于 `URLField`，允许指定默认的 URL 方案。

- 为了提高可访问性，进行了以下更改：

  - 现在表单字段包括 `aria-describedby` HTML 属性，以使屏幕阅读器能够将表单字段与其帮助文本关联起来。

  - 无效的表单字段现在包括 `aria-invalid="true"` HTML 属性。

#### 国际化

- 现在支持维吾尔语，并提供翻译。

#### 迁移

- 现在支持对使用 `functools.cache()` 或 `functools.lru_cache()` 装饰的函数进行序列化，无需编写自定义序列化器。

#### 模型

- `QuerySet.update_or_create()` 和 `QuerySet.aupdate_or_create()` 方法的新 `create_defaults` 参数允许为创建操作指定不同的字段值。

- `BaseConstraint`、`CheckConstraint` 和 `UniqueConstraint` 的新 `violation_error_code` 属性允许自定义在 模型验证 过程中引发的 `ValidationError` 的 `code`。

- `Model.save()` 的 force_insert 参数现在允许指定必须强制插入的父类的元组。

- 当启用 `update_conflicts` 参数时，`QuerySet.bulk_create()` 和 `QuerySet.abulk_create()` 方法现在会为每个模型实例设置主键（如果数据库支持的话）。

- 新的 `UniqueConstraint.nulls_distinct` 属性允许自定义在 PostgreSQL 15+ 上对 `NULL` 值的处理方式。

- 新的 `aget_object_or_404()` 和 `aget_list_or_404()` 异步快捷方式允许异步获取对象。

- 新的 `aprefetch_related_objects()` 函数允许异步预取模型实例。

- `QuerySet.aiterator()` 现在支持之前对 `prefetch_related()` 的调用。

- 在 MariaDB 10.7+ 上，`UUIDField` 现在将创建为 `UUID` 列，而不是 `CHAR(32)` 列。有关 迁移现有的在 MariaDB 10.7+ 上的 UUIDField 的更多详细信息，请参阅迁移指南。

- Django 现在支持 oracledb 版本 1.3.2 或更高版本。从此版本开始，对 `cx_Oracle` 的支持已被弃用，并将在 Django 6.0 中移除。

#### 分页

- 新的 `django.core.paginator.Paginator.error_messages` 参数允许自定义由 `Paginator.page()` 引发的错误消息。

#### 信号

- 新的 `Signal.asend()` 和 `Signal.asend_robust()` 方法允许异步信号分发。信号接收器可以是同步或异步的，将自动适应正确的调用方式。

#### 模板

- 新的 `escapeseq` 模板过滤器将 `escape` 应用于序列的每个元素。

#### 测试

- `Client` 和 `AsyncClient` 现在提供异步方法，使用 `a` 前缀：`asession()`、`alogin()`、`aforce_login()` 和 `alogout()`。

- `AsyncClient` 现在支持 `follow` 参数。

- `DiscoverRunner` 现在允许使用 `test --durations` 选项（适用于 Python 3.12+）显示最慢测试的持续时间。

#### 验证器

- `StepValueValidator` 的新 `offset` 参数允许为有效值指定偏移量。

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

### 数据库后端 API

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

- 如果数据库不支持将数据库函数用作默认值，则应将 `DatabaseFeatures.supports_expression_defaults` 设置为 `False`。

- 如果数据库不支持在 `INSERT` 查询中使用 `DEFAULT` 关键字，应将 `DatabaseFeatures.supports_default_keyword_in_insert` 设置为 `False`。

- 如果数据库不支持在批量 `INSERT` 查询中使用 `DEFAULT` 关键字，应将 `DatabaseFeatures.supports_default_keyword_in_bulk_insert` 设置为 `False`。

### `django.contrib.gis`

- 移除对 GDAL 2.2 和 2.3 的支持。

- 移除对 GEOS 3.6 和 3.7 的支持。

### `django.contrib.sitemaps`

- 移除了 `django.contrib.sitemaps.ping_google()` 函数和 `ping_google` 管理命令，因为 Google Sitemaps 的 ping 端点已被弃用，并将于 2024 年 1 月被移除。

- 移除了 `django.contrib.sitemaps.SitemapNotFound` 异常类。

### 不再支持 MySQL 版本低于 8.0.11。

不再支持 MySQL 8.0.x 系列的预发布版本。Django 5.0 支持 MySQL 8.0.11 及更高版本。

### 在使用 `QuerySet.update_or_create()` 时，可能现在需要使用 `create_defaults__exact`。

`QuerySet.update_or_create()` 现在支持参数 `create_defaults`。因此，任何在 `update_or_create()` 中使用具有名为 `create_defaults` 的字段的模型应该在查找中使用 `create_defaults__exact` 指定该字段。

### 迁移现有的在 MariaDB 10.7+ 上的 `UUIDField`

在 MariaDB 10.7+ 中，现在将 `UUIDField` 创建为 `UUID` 列，而不再是 `CHAR(32)` 列。因此，在 Django 版本小于 5.0 中创建的任何 `UUIDField` 都应该替换为由 `CHAR(32)` 支持的 `UUIDField` 子类:

    class Char32UUIDField(models.UUIDField):
        def db_type(self, connection):
            return "char(32)"

        def get_db_prep_value(self, value, connection, prepared=False):
            value = super().get_db_prep_value(value, connection, prepared)
            if value is not None:
                value = value.hex
            return value

例子：

    class MyModel(models.Model):
        uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)

应该变成：

    class Char32UUIDField(models.UUIDField): ...

    class MyModel(models.Model):
        uuid = Char32UUIDField(primary_key=True, default=uuid.uuid4)

运行 `makemigrations` 命令将生成一个包含无操作的 `AlterField` 操作的迁移。

### 杂项

- 未记录的 `BaseModelFormSet.save_existing()` 方法的 `instance` 参数已重命名为 `obj`。

- 未记录的 `django.contrib.admin.helpers.checkbox` 已被移除。

- 在 SQLite 上，整数字段现在会被验证为 64 位整数，以匹配 `sqlite3` 的行为。

- 未记录的 `Query.annotation_select_mask` 属性已从字符串集更改为有序的字符串列表。

- 如果未设置 `width_field` 和 `height_field`，则不再在 `post_init` 信号上调用 `ImageField.update_dimension_fields()`。

- 在 Oracle 上，`Now` 数据库函数现在使用 `LOCALTIMESTAMP` 而不是 `CURRENT_TIMESTAMP`。

- `AdminSite.site_header` 现在呈现在一个 `<div>` 标签中，而不是 `<h1>`。屏幕阅读器用户依赖标题元素在页面内导航。拥有两个 `<h1>` 元素会引起混淆，而且站点标题在所有页面上都重复出现，没有帮助。

- 为了提高可访问性，管理员的主要内容区域和页眉内容区域现在呈现在 `<main>` 和 `<header>` 标签中，而不是 `<div>`。

- 在没有原生支持 SQL `XOR` 运算符的数据库上，作为异或（`XOR`）运算符的 `^` 现在会返回被奇数个操作数匹配的行，而不是严格匹配一个操作数。这与 MySQL、MariaDB 和 Python 的行为一致。

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

- `selenium` 的最低支持版本已从 3.8.0 增加到 4.8.0。

- `AlreadyRegistered` 和 `NotRegistered` 异常已从 `django.contrib.admin.sites` 移动到 `django.contrib.admin.exceptions`。

- SQLite 的最低支持版本已从 3.21.0 增加到 3.27.0。

- 不再支持 `cx_Oracle` 版本小于 8.3。

- 在应用程序注册表完全填充之前执行 SQL 查询现在会引发 `RuntimeWarning`。

- 对于非 UTF-8 编码的请求和 application/x-www-form-urlencoded 内容类型，将引发 `BadRequest` 异常。有关详细信息，请参阅 RFC 1866。

- `colorama` 的最低支持版本已增加到 0.4.6。

- `docutils` 的最低支持版本已增加到 0.19。

- 过滤查询集以防止整数溢出现在始终返回空查询集。因此，在这种情况下，你可能需要使用 `ExpressionWrapper()` 来对整数字段进行算术运算时进行 显式包装。

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

### 杂项

- `DjangoDivFormRenderer` 和 `Jinja2DivFormRenderer` 过渡的表单渲染器已被弃用。

- 将位置参数 `name` 和 `violation_error_message` 传递给 `BaseConstraint` 已被弃用，建议使用关键字参数方式。

- `request` 已添加到 `ModelAdmin.lookup_allowed()` 的签名中。不接受此参数的 `ModelAdmin` 子类的支持已被弃用。

- `ForeignObject` 和 `ForeignObjectRel` 的 `get_joining_columns()` 方法已被弃用。从 Django 6.0 开始，`django.db.models.sql.datastructures.Join` 将不再回退到 `get_joining_columns()`。子类应该改为实现 `get_joining_fields()`。

- `ForeignObject.get_reverse_joining_columns()` 方法已被弃用。

- The default scheme for `forms.URLField` will change from `"http"` to `"https"` in Django 6.0. Set `FORMS_URLFIELD_ASSUME_HTTPS` transitional setting to `True` to opt into assuming `"https"` during the Django 5.x release cycle.

- `FORMS_URLFIELD_ASSUME_HTTPS` 过渡设置已被弃用。

- 不推荐在不传递 args 或 kwargs 的情况下调用 `format_html()`。

- 对 `cx_Oracle` 的支持已被弃用，建议使用 oracledb 1.3.2+ Python 驱动程序。

- `DatabaseOperations.field_cast_sql()` 已被弃用，建议使用 `DatabaseOperations.lookup_cast()`。从 Django 6.0 开始，`BuiltinLookup.process_lhs()` 将不再调用 `field_cast_sql()`。第三方数据库后端应该改为实现 `lookup_cast()`。

- `django.db.models.enums.ChoicesMeta` 元类已更名为 `ChoicesType`。

- `Prefetch.get_current_queryset()` 方法已被弃用。

- 相关管理器和描述符的 `get_prefetch_queryset()` 方法已被弃用。从 Django 6.0 开始，`get_prefetcher()` 和 `prefetch_related_objects()` 将不再回退到 `get_prefetch_queryset()`。子类应该改为实现 `get_prefetch_querysets()`。

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

这些功能已经完成了它们的弃用周期，并在 Django 5.0 中被移除。

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

- `SERIALIZE` 测试设置已被移除。

- 未记录的 `django.utils.baseconv` 模块已被移除。

- 未记录的 `django.utils.datetime_safe` 模块已被移除。

- `USE_TZ` 设置的默认值已从 `False` 更改为 `True`。

- 在不在请求上下文之外构建的站点地图的默认协议已从 `'http'` 更改为 `'https'`。

- `DiscoverRunner.build_suite()` 和 `DiscoverRunner.run_tests()` 的 `extra_tests` 参数已被移除。

- 当没有行时，`django.contrib.postgres.aggregates.ArrayAgg`、`JSONBAgg` 和 `StringAgg` 聚合现在不再返回 `[]`、`[]` 和 `''`，而是返回 `None`。

- `USE_L10N` 设置已被移除。

- `USE_DEPRECATED_PYTZ` 过渡设置已被移除。

- 对于 `pytz` 时区的支持已被移除。

- `is_dst` 参数已从以下地方移除：

  - `QuerySet.datetimes()`

  - `django.utils.timezone.make_aware()`

  - `django.db.models.functions.Trunc()`

  - `django.db.models.functions.TruncSecond()`

  - `django.db.models.functions.TruncMinute()`

  - `django.db.models.functions.TruncHour()`

  - `django.db.models.functions.TruncDay()`

  - `django.db.models.functions.TruncWeek()`

  - `django.db.models.functions.TruncMonth()`

  - `django.db.models.functions.TruncQuarter()`

  - `django.db.models.functions.TruncYear()`

- `django.contrib.gis.admin.GeoModelAdmin` 和 `OSMGeoAdmin` 类已被移除。

- 未记录的 `BaseForm._html_output()` 方法已被移除。

- 在渲染 `ErrorDict` 和 `ErrorList` 时返回 `str` 而不是 `SafeString` 的能力已被移除。

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

- `SitemapIndexItem.__str__()` 方法已被移除。

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

- `django.utils.functional.cached_property()` 的 `name` 参数已被移除。

- `django.contrib.postgres.constraints.ExclusionConstraint` 的 `opclasses` 参数已被移除。

- 已移除将 `errors=None` 传递给 `SimpleTestCase.assertFormError()` 和 `assertFormsetError()` 的未记录能力。

- `django.contrib.sessions.serializers.PickleSerializer` 已被移除。

- 不再允许在预取相关对象但没有提供 `chunk_size` 参数的查询集上使用 `QuerySet.iterator()`。

- 不再允许将未保存的模型实例传递给相关的过滤器。

- 在 `RemoteUserBackend.configure_user()` 子类的签名中需要包含 `created=True`。

- 已移除通过 `GET` 请求在 `django.contrib.auth.views.LogoutView` 和 `django.contrib.auth.views.logout_then_login()` 中进行登出的支持。

- `django.utils.timezone.utc` 到 `datetime.timezone.utc` 的别名已被移除。

- 不再允许将响应对象和表单/表单集名称传递给 `SimpleTestCase.assertFormError()` 和 `assertFormSetError()`。

- `django.contrib.gis.admin.OpenLayersWidget` 已被移除。

- `django.contrib.auth.hashers.CryptPasswordHasher` 已被移除。

- `"django/forms/default.html"` 和 `"django/forms/formsets/default.html"` 模板已被移除。

- 默认的表单和表单集呈现样式已更改为基于 div 的样式。

- 不再允许向 `Expression.asc()` 和 `Expression.desc()` 方法以及 `OrderBy` 表达式传递 `nulls_first=False` 或 `nulls_last=False`。