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 选项中定义的 Checkuniqueexclusion 约束现在在 模型验证 期间进行检查。

表单渲染的可访问性

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

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

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

请查看 :ref:`下面的表单部分 <forms-4.1>`以获取完整的详细信息。

次要特性

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

django.contrib.postgres

django.contrib.sitemaps

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

django.contrib.staticfiles

数据库后端

  • 第三方数据库后端现在可以使用 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.DjangoDivFormRendererdjango.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_nameformset_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 参数允许防止创建新对象。

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

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

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

  • IntegerFieldFloatFieldDecimalField 现在可以选择接受一个 step_size 参数。这用于设置 step HTML 属性,并在表单提交时进行验证。

国际化

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

管理命令

迁移

模型

  • 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 的数据库,查询将被转换为使用 ANDORNOT 的等效查询。
  • 新的 Field.non_db_attrs 属性允许自定义不影响列定义的字段属性。
  • 在 PostgreSQL 上,AutoFieldBigAutoFieldSmallAutoField 现在作为标识列(identity columns)创建,而不是带有序列的序列列(serial columns)。

请求和响应

安全

信号

模板

  • 在包装 json_script 模板过滤器时,不再需要 HTML <script> 元素的 id 属性。
  • 在开发环境中,当 DEBUGTrue 且未指定 OPTIONS['loaders'] 时,现在会启用 cached template loader。如果需要,您可以指定 OPTIONS['loaders'] 来覆盖这个设置。

测试

URLs

实用程序

  • SimpleLazyObject 现在支持加法操作。
  • mark_safe() 现在保留懒惰对象。

验证器

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

4.1 版本中的不兼容变更

数据库后端 API

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

  • BaseDatabaseFeatures.has_case_insensitive_likeTrue 改为 False,以反映大多数数据库的行为。
  • DatabaseIntrospection.get_key_columns() 已被移除。请改用 DatabaseIntrospection.get_relations()
  • DatabaseOperations.ignore_conflicts_suffix_sql() 方法被替换为 DatabaseOperations.on_conflict_suffix_sql(),它接受 fieldson_conflictupdate_fieldsunique_fields 参数。
  • DatabaseOperations.insert_statement() 方法的 ignore_conflicts 参数被替换为接受 django.db.models.constants.OnConflicton_conflict 参数。
  • DatabaseOperations._convert_field_to_tz() 被替换为 DatabaseOperations._convert_sql_to_tz(),它接受 sqlparamstzname 参数。
  • DatabaseOperations 上的多个日期和时间方法现在接受 sqlparams 参数,而不再接受 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

杂项

  • ForeignKeyManyToManyFieldModel 实例上。这个变更在 Django 4.1.2 中被撤销了。
  • Django 的测试运行器现在对被标记为 unittest.expectedFailure() 的测试出现意外成功时返回非零错误代码。
  • CsrfViewMiddleware 现在不再像在 DOM 中遮蔽 CSRF 令牌一样遮蔽 CSRF cookie。
  • CsrfViewMiddleware 现在使用 request.META['CSRF_COOKIE'] 来存储未遮蔽的 CSRF 密钥,而不是遮蔽版本。这是一个未记录的、私有的 API。
  • ModelAdmin.actionsinlines 属性现在默认为空元组,而不是空列表,以防止意外的变更。
  • 在 CSS 表单媒体<link> 标签中不再包含 type="text/css" 属性。
  • formset:addedformset: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_strsURLPattern.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 方式注销登录

通过 GET 请求注销到 内置的注销视图 已经不推荐使用。请改为使用 POST 请求。

如果您想保留 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.ExclusionConstraintopclasses 参数已被弃用,而应使用 ExclusionConstraint.expressions 中的 OpClass()。要使用它,你需要在 INSTALLED_APPS 中添加 'django.contrib.postgres'

    在进行这些更改后,makemigrations 将生成一个新的迁移,其中包含两个操作:RemoveConstraintAddConstraint。由于这些更改不影响数据库架构,可以使用 SeparateDatabaseAndState 操作来仅更新迁移状态而不运行任何 SQL。将生成的操作移动到 SeparateDatabaseAndStatestate_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.utcdatetime.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=Falsenulls_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.EmailValidatorwhitelist 参数和 domain_whitelist 属性已被移除。
  • default_app_config 应用程序配置变量已被移除。
  • TransactionTestCase.assertQuerysetEqual() 在与字符串值进行比较时不再调用 repr() 方法来处理查询集。
  • django.core.cache.backends.memcached.MemcachedCache 已被移除。
  • django.contrib.messages.storage.cookie.CookieStorage 使用的 Django 3.2 之前的消息格式的支持已被移除。
Back to Top