Django 3.1 版本发行说明

2020 年 8 月 4 日

欢迎来到 Django 3.1 版本!

此版本说明涵盖了一些 新特性 ,以及从 Django 3.0 或更早版本升级时需要注意的 向后不兼容 的地方。我们已经 删除了一些过期的功能 ,并且已经开始 淘汰一些特性

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

Python 兼容性

Django 3.1 支持 Python 3.6、3.7、3.8 和 3.9(从 3.1.3 开始)。我们 强烈推荐 且官方只支持每个系列的最新版本。

Django 3.1 新特性

异步视图和中间件支持

Django 现在支持完全异步的请求路径,包括:

要开始使用异步视图,你需要使用 async def 来声明一个视图:

  1. async def my_view(request):
  2. await asyncio.sleep(0.5)
  3. return HttpResponse("Hello, async world!")

无论你是在 WSGI 或 ASGI 模式下运行,都支持所有的异步功能。但是,在 WSGI 模式下使用 async 代码会有性能上的惩罚。你可以在 异步支持 文档中阅读更多的具体内容。

你可以自由地混合异步和同步视图、中间件和测试,只要你愿意。Django 会确保你最终使用正确的执行上下文。我们希望大多数项目会保持大部分视图的同步,只有少数视图在异步模式下运行,但这完全是你的选择。

Django 的 ORM、缓存层和其他做长期网络调用的代码还不支持异步访问。我们希望在即将发布的版本中增加对它们的支持。但是,异步视图是很理想的,如果你在视图里面做了大量的 API 或 HTTP 调用,你现在可以原生地将所有这些 HTTP 调用并行进行,以大大加快你的视图的执行速度。

异步支持应该是完全向后兼容的,我们已经尝试确保它不会对你现有的同步代码造成速度上的倒退。它应该不会对任何现有的 Django 项目产生明显的影响。

JSONField 适用于所有支持的数据库后端。

Django 现在包含 models.JSONFieldforms.JSONField,可以在所有支持的数据库后端使用。这两个字段都支持使用自定义 JSON 编码器和解码器。模型字段支持自省、查找和变换,这些功能以前只有 PostgreSQL 才有:

  1. from django.db import models
  2. class ContactInfo(models.Model):
  3. data = models.JSONField()
  4. ContactInfo.objects.create(
  5. data={
  6. "name": "John",
  7. "cities": ["London", "Cambridge"],
  8. "pets": {"dogs": ["Rufus", "Meg"]},
  9. }
  10. )
  11. ContactInfo.objects.filter(
  12. data__name="John",
  13. data__pets__has_key="dogs",
  14. data__cities__contains="London",
  15. ).delete()

如果你的项目使用了 django.contrib.postgres.fields.JSONField,加上相关的表单字段和变换,你应该调整使用新的字段,并生成和应用数据库迁移。目前,旧的字段和变换体作为新字段的引用留存下来,并且 从这个版本开始取消

DEFAULT_HASHING_ALGORITHM 配置

新的 DEFAULT_HASHING_ALGORITHM 过渡设置允许指定用于编码 cookie、管理员站点中的密码重置令牌、用户会话以及由 django.core.signing.Signerdjango.core.signing.dumps() 创建的签名的默认哈希算法。

在 Django 3.1 中添加了对 SHA-256 的支持。如果您正在将同一项目的多个实例升级到 Django 3.1,您应该在过渡期间将 DEFAULT_HASHING_ALGORITHM 设置为 'sha1',以便与旧版本的 Django 兼容。请注意,这需要 Django 3.1.1+。一旦完成到 3.1 的过渡,您可以停止覆盖 DEFAULT_HASHING_ALGORITHM

因为在 Django 4.0 中,对使用 SHA-1 算法的令牌、cookie、会话和签名的支持将被取消,所以这个配置从这个版本开始就被取消了。

次要特性

django.contrib.admin

  • 新的 django.contrib.admin.EmptyFieldListFilterModelAdmin.list_filter 允许在管理的变更列表视图中过滤空值(空字符串和空值)。

  • 管理员更改列表视图右侧的过滤器现在包含一个清除所有过滤器的链接。

  • 管理员现在在大屏幕上有一个侧栏,以便于导航。它是默认启用的,但可以通过使用一个自定义的 AdminSite 和设置 AdminSite.enable_nav_sidebarFalse 来禁用。

    渲染侧边栏需要访问当前请求,以便设置 CSS 和 ARIA 角色的负担。这就需要使用 OPTIONS'context_processors' 选项中的 'django.template.context_processors.request'

  • 最初的空 extra 内联现在可以被删除,与动态创建的内联相同。

  • XRegExp 从 2.0.0 版本升级到 3.2.0。

  • jQuery 从 3.4.1 版本升级到 3.5.1。

  • Select2 库从 4.0.7 版本升级到 4.0.13。

django.contrib.auth

  • PBKDF2 密码哈希的默认迭代次数从 180,000 增加到 216,000。
  • 新的 PASSWORD_RESET_TIMEOUT 配置允许定义密码重置链接的有效秒数。我们鼓励这样做,而不是使用被废弃的 PASSWORD_RESET_TIMEOUT_DAYS 配置,后者将在 Django 4.0 中被删除。
  • 密码重置机制现在使用 SHA-256 散列算法。在 Django 4.0 之前,对使用旧的散列算法的令牌的支持仍然存在。
  • AbstractBaseUser.get_session_auth_hash() 现在使用 SHA-256 散列算法。在 Django 4.0 之前,对使用旧的散列算法的用户会话的支持仍然存在。

django.contrib.contenttypes

django.contrib.gis

  • relate 查找现已在 MariaDB 上支持。
  • 添加了 LinearRing.is_counterclockwise 属性。
  • AsGeoJSON 现已在 Oracle 上支持。
  • 添加了 AsWKBAsWKT 函数。
  • 增加了对 PostGIS 3 和 GDAL 3 的支持。

django.contrib.humanize

  • intword 模板过滤器现在支持负整数。

django.contrib.postgres

django.contrib.sessions

  • SESSION_COOKIE_SAMESITE 配置现在允许 'None' (字符串)值明确表示所有同站和跨站请求都会发送 cookie。

django.contrib.staticfiles

缓存

CSRF

  • CSRF_COOKIE_SAMESITE 配置现在允许 'None' (字符串)值来明确说明所有同站和跨站请求都会发送 cookie。

电子邮件

错误报告

文件存储

  • FileSystemStorage.save() 方法现在支持 pathlib.Path
  • FileFieldImageField 现在可以接受 storage 的调用。这允许你在运行时修改所使用的存储,例如为不同的环境选择不同的存储。

表单

国际化

  • LANGUAGE_COOKIE_SAMESITE 配置现在允许 'None' (字符串)值明确表示所有同站和跨站请求都会发送 cookie。
  • 增加了对阿尔及利亚阿拉伯语、伊博语、吉尔吉斯语、塔吉克语和土库曼语的支持和翻译。

管理命令

  • 新的 check —database 选项允许指定数据库别名,以便运行 database 系统检查。以前,通过向命令传递 database 标签,为所有设置的 DATABASES 启用这些检查。
  • 新的 migrate —check 选项使命令在检测到未应用的迁移时以非零状态退出。
  • CommandError 的新 ``returncode``参数允许自定义管理命令的退出状态。
  • 新的 dbshell — ARGUMENTS 选项允许向数据库的命令行客户端传递额外的参数。
  • flushsqlflush 命令现在包括 SQL 来重置 SQLite 上的序列。

模型

  • 新的 ExtractIsoWeekDay 函数从 DateFieldDateTimeField 中提取 ISO-8601 周天,新的 iso_week_day 查询可以按 ISO-8601 周天查询。
  • QuerySet.explain() 现在支持:
    • MySQL 8.0.16+ 上的 TREE 格式,
    • MySQL 8.0.18+ 和 MariaDB 上的 analyze 选项。
  • 添加了 PositiveBigIntegerField,它的作用很像 PositiveIntegerField,只是它只允许在一定(依赖于数据库的)限制下取值。从 09223372036854775807 的值在 Django 支持的所有数据库中都是安全的。
  • 新的 RESTRICT 选项为 ForeignKey` OneToOneFieldon_delete 参数模拟了 SQL 约束 ON DELETE RESTRICT 的行为。
  • CheckConstraint.check 现在支持布尔表达式。
  • RelatedManager.add()create()set() 方法现在接受可调用对象参数作为 through_defaults 参数的值。
  • QuerySet.datetimes() 的新 is_dst 参数决定了如何处理不存在和不明确的日期。
  • 新的 F 表达式 bitxor() 方法允许 bitwise XOR 操作
  • QuerySet.bulk_create() 在使用 MariaDB 10.5+ 时,现在可以设置对象的主键。
  • DatabaseOperations.sql_flush() 方法现在可以在 MySQL 上生成更有效的 SQL,对于不需要重置序列的表,使用 DELETE 而不是 TRUNCATE 语句。
  • SQLite 函数现已在 Python 3.8+ 上被标记为 deterministic。这允许在检查约束和部分索引中使用它们。
  • 新的 UniqueConstraint.deferrable 属性允许创建可推迟的唯一约束。

分页

  • Paginator 现在可以迭代产生其页面。

请求和响应

安全

模板

  • 重新命名的 translateblocktranslate 模板标签被引入,用于模板代码的国际化。旧的 transblocktrans 模板标签的别名继续工作,并将在可预见的未来保留。
  • include 模板标签现在接受模板名称的可迭代对象。

测试

  • SimpleTestCase 现在实现了 debug() 方法,允许在不收集结果和捕获异常的情况下运行测试。这可以用来支持在调试器下运行测试。
  • 新的 MIGRATE 测试数据库配置允许在创建测试数据库时禁止迁移。
  • Django 测试运行器现在支持 test —buffer 选项,以丢弃通过测试的输出。
  • DiscoverRunner 现在会跳过对非 测试所引用 的数据库进行系统检查。
  • TransactionTestCase 关闭现在在 MySQL 上的速度更快了,这是因为 flush 命令的改进。作为一个副作用,后者不会再在关闭时自动重置序列。如果你的测试需要这个功能,请启用 TransactionTestCase.reset_sequences

URLs

  • Path 转换器 现在可以在 to_url() 中引发 ValueError,在反查 URL 时表示不匹配。

实用程序

杂项

3.1 中的不向后兼容的变更

数据库后端 API

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

  • DatabaseOperations.fetch_returned_insert_columns() 现在需要一个额外的 returning_params 参数。
  • connection.timezone 属性现在默认为 'UTC,或者当 USE_TZTrue 时,支持时区的数据库上的 TIME_ZONE。此前,在支持时区的数据库上是 None
  • connection._nodb_connection 属性改为 connection._nodb_cursor() 方法,现在返回一个产生游标的上下文管理器,并在退出 with 语句后自动关闭游标和连接。
  • DatabaseClient.runshell() 现在需要一个额外的 parameters 参数,作为传递给命令行客户端的额外参数列表。
  • DatabaseOperations.sql_flush()sequences 位置参数被只用关键字的布尔参数 reset_sequences 取代。如果 True,截断表的序列将被重置。
  • DatabaseOperations.sql_flush()allow_cascade 参数现在是一个纯关键字的参数。
  • DatabaseOperations.execute_sql_flush()using 位置参数被删除。该方法现在使用被调用实例的数据库。
  • 第三方数据库后端必须实现对 JSONField 的支持,或者将 DatabaseFeatures.supports_json_field 设置为 False。如果不支持存储基元,则设置 DatabaseFeatures.supports_primitives_in_json_fieldFalse。如果 JSON 的数据类型为真,则设置 DatabaseFeatures.has_native_json_fieldTrue。如果不支持 jsonfield.containsjsonfield.contains_by,则将 DatabaseFeatures.support_json_field_contains 设置为 False
  • 第三方数据库后端必须实现对 JSONField 的自省,或者将 can_introspect_json_field 设置为 False

丢弃了对 MariaDB 10.1 的支持

对 MariaDB 10.1 的上游支持在 2020 年 10 月结束。Django 3.1 支持 MariaDB 10.2 及以上版本。

contrib.admin 浏览器支持

管理不再支持传统的 Internet Explorer 浏览器。关于支持的浏览器,请参见 管理常见问题

AbstractUser.first_namemax_length 增加到 150

包含了 django.contrib.auth.models.User.first_name 的迁移。如果你有一个继承自 AbstractUser 的自定义用户模型,你将需要为你的用户模型生成并应用数据库迁移。

如果你想保留 first name 的 30 个字符限制,请使用自定义表单:

  1. from django import forms
  2. from django.contrib.auth.forms import UserChangeForm
  3. class MyUserChangeForm(UserChangeForm):
  4. first_name = forms.CharField(max_length=30, required=False)

如果你想在管理中编辑用户时保留这个限制,请将 UserAdmin.form 设置为使用这个表单:

  1. from django.contrib.auth.admin import UserAdmin
  2. from django.contrib.auth.models import User
  3. class MyUserAdmin(UserAdmin):
  4. form = MyUserChangeForm
  5. admin.site.unregister(User)
  6. admin.site.register(User, MyUserAdmin)

杂项

  • cache 使用的缓存密钥和 make_template_fragment_key() 生成的缓存密钥与旧版本 Django 生成的密钥不同。升级到 Django 3.1 后,第一次请求任何之前缓存的模板片段都会被缓存错过。
  • set_language() 视图中返回重定向回退或 204 HTTP 响应背后的逻辑现在是基于 Accept HTTP 头而不是 X-Requested-With HTTP 头的存在。
  • django.db.models.querydjango.db.models.sqldjango.db.models.sql.datastructures 中的 django.core.exceptions.EmptyResultSet 的兼容性导入被移除。
  • 删除了 django.db.models.fielddjango.core.exceptions.FieldDoesNotExist 的兼容性导入。
  • 删除了 django.forms.utils.pretty_name()django.forms.boundfield.BoundField 的兼容性导入。
  • django.template.base 中的 ContextContextPopExceptionRequestContext 的兼容性导入被移除。
  • 删除了 django.contrib.admin.helpers.ACTION_CHECKBOX_NAME 中的兼容性导入。
  • 设置为相对路径的 STATIC_URLMEDIA_URL 配置现在以服务器提供的 SCRIPT_NAME 的值为前缀(如果没有设置,则为 /)。这一变化不应影响设置为有效 URL 或绝对路径的配置。
  • ConditionalGetMiddleware 不再为空 content 的响应添加 ETag 头。
  • django.utils.disturators.classproperty() 装饰器被公开并移到 django.utils.functional.classproperty()
  • floatform 模板过滤器现在对四舍五入为零的负数输出(正)``0```。
  • Meta.orderingMeta.unique_together <django.db.models.Options.unique_together>` 模块中模型的选项,以前是元组,现在是列表。
  • 管理日历部件现在根据开放组规范处理两位数的年份,即 69 和 99 之间的值被映射到上一个世纪,0 和 68 之间的值被映射到当前世纪。
  • DATETIME_INPUT_FORMATS 的默认列表中删除了仅限日期的格式。
  • 当初始数据存在时,FileInput 小部件不再使用 required HTML 属性进行渲染。
  • 删除了未记录的 django.views.debug.ExceptionReporterFilter 类。根据 自定义错误报告 文档,与 DEFAULT_EXCEPTION_REPORTER_FILTER 一起使用的类需要继承 django.views.debug.SafeExceptionReporterFilter
  • cache_page() 装饰器设置的缓存超时现在优先于 Cache-Control 头的 max-age 指令。
  • ForeignKey.to_field 参数中提供一个非本地的远程字段,现在会引发 FieldError
  • SECURE_REFERRER_POLICY 现在默认为 'same-origin'。更多细节请参见 新变化 安全章节
  • check 管理命令现在只对使用 check —database 选项指定的数据库别名运行 database 系统检查。
  • migrate 管理命令现在只运行 database 系统检查要迁移的数据库。
  • 管理 CSS 类 row1row2 被删除,取而代之的是 :nth-child(odd):nth-child(even) 伪类。
  • make_password() 函数现在要求其参数为字符串或字节。其他类型的参数应该显式地转换为其中之一。
  • 删除了 AsKML 函数中未记录的 version 参数。
  • JSON 和 YAML 序列化器,由 dumpdata 使用,现在默认使用 Unicode 转储所有数据。如果你需要以前的行为,传递 ensure_ascii=True 给 JSON 序列化器,或者 allow_unicode=False 给 YAML 序列化器。
  • 自动重新加载器不再监控内置 Django 翻译文件的变化。
  • mysqlclient 的最低支持版本从 1.3.13 增加到 1.4.0。
  • 未记录的 django.contrib.postgres.forms.InvalidJSONInputdjango.contrib.postgres.forms.JSONString 被移至 django.forms.field
  • 删除了未记录的 django.contrib.postgres.field.jsonb.JsonAdapter 类。
  • {% localize off %} 标签和 unlocalize 过滤器不再遵守 DECIMAL_SEPARATOR 配置。
  • asgiref 的最低支持版本从 3.2 增加到 3.2.10。
  • Media 类现在不使用 type 属性来渲染 <script> 标签,以遵循 WHATWG 建议
  • ModelChoiceIterator,由 ModelChoiceFieldModelMultipleChoiceField 使用,现在产生 2 个包含 ModelChoiceIteratorValue 实例的选择,作为每个选择的第一个 value 元素。在大多数情况下,这个代理是透明的,但如果你需要 field 值本身,请使用 ModelChoiceIteratorValue.value 属性代替。

在 3.1 中被废弃的功能

PostgreSQL 的 JSONField

django.contrib.postgres.field.JSONFielddjango.contrib.postgres.forms.JSONField 被废弃,改用 models.JSONFieldforms.JSONField

未记录的 django.contrib.postgres.fields.jsonb.KeyTransformdjango.contrib.postgres.fields.jsonb.KeyTextTransform 也被弃用,改用 django.db.models.fields.json 中的变换。

新的 JSONFieldKeyTransformKeyTextTransform 可用于所有支持的数据库后端。

杂项

  • PASSWORD_RESET_TIMEOUT_DAYS 配置已被取消,改为 PASSWORD_RESET_TIMEOUT

  • 未记录的 isnull 查找使用非布尔值作为右侧的用法已被废弃,请使用 TrueFalse 代替。

  • 勉强记录的 django.db.models.query_utils.InvalidQuery 异常类被废弃,取而代之的是 FieldDoesNotExistFieldError

  • django-admin.py 的入口点已被废弃,改为 django-admin

  • HttpRequest.is_ajax() 方法已被废弃,因为它依赖于 jQuery 特定的方式来表示 AJAX 调用,而当前的用法倾向于使用 JavaScript Fetch API 。根据你的用例,你可以写你自己的 AJAX 检测方法,或者使用新的 HttpRequest.accepts() 方法,如果你的代码依赖于客户端 Accept HTTP 头。

    如果你正在编写自己的 AJAX 检测方法,request.is_ajax() 可以完全复制为 request.headers.get('x-requested-with') == 'XMLHttpRequest'

  • 传递 None 作为 django.utils.deprecation.MiddlewareMixin.__init__() 的第一个参数是过时的。

  • CookieStorage 使用的 cookie 值的编码格式与旧版本 Django 生成的格式不同。在 Django 4.0 之前,仍然支持旧的格式。

  • 会话的编码格式与旧版 Django 生成的格式不同。在 Django 4.0 之前,仍然支持旧的格式。

  • Signal 的纯文档化 providing_args 参数已被废弃。如果你依赖这个参数作为文档,你可以将文本移到代码注释或 docstring 中。

  • 没有 length 参数的情况下调用 django.utils.crypto.get_random_string() 已被废弃。

  • ModelMultipleChoiceFieldlist 信息已被弃用,改为 invalid_list

  • QuerySet.order_by() 传递原始列别名已经被废弃。通过事先在 RawSQL 中传递别名,可以达到同样的效果。

  • NullBooleanField 模型字段被废弃,改为 BooleanField(null=True)

  • django.conf.urls.url()django.urls.re_path() 别名已被废弃。

  • {% ifequal %}{% ifnotequal %} 模板标签已被废弃,改为 {% if %}{% if %} 涵盖了所有的用例,但如果你需要继续使用这些标签,可以将它们从 Django 中提取到一个模块中,并作为一个内置标签包含在 ‘buildins’ 选项中的 OPTIONS 中。

  • DEFAULT_HASHING_ALGORITHM 过渡性配置已废弃。

3.1 中删除的功能

这些功能已经到了废弃周期,在 Django 3.1 中被删除。

参见 在 2.2 中被废弃的功能,了解这些变化的细节,包括如何删除这些功能的使用。

  • django.utils.timezone.FixedOffset 被删除。
  • django.core.paginator.QuerySetPaginator 被删除。
  • 一个模型的 Meta.ordering 不影响 GROUP BY 的查询。
  • django.contrib.postgres.fields.FloatRangeFielddjango.contrib.postgres.forms.FloatRangeField 被删除。
  • FILE_CHARSET 配置被删除。
  • django.contrib.staticfiles.storage.CachedStaticFilesStorage 被删除。
  • RemoteUserBackend.configure_user() 方法需要 request 作为第一个位置参数。
  • 取消对 SimpleTestCase.allow_database_queriesTransactionTestCase.multi_db 的支持。