Django 3.2 版本发行说明

2021 年 4 月 6 日

欢迎来到 Django 3.2 版本!

这些发行说明涵盖了 新功能,以及一些 向后不兼容的变化,当你从 Django 3.1 或更早版本升级时,你需要注意。我们已经 开始了一些功能的废弃过程

如果你要更新现有的项目,请看 How to upgrade Django to a newer version 指南。

Django 3.2 被指定为 长期支持发行。它将在发行后至少三年内获得安全更新。对前一个 LTS,即 Django 2.2 的支持将于 2022 年 4 月结束。

Python 兼容性

Django 3.2 支持 Python 3.6、3.7、3.8、3.9 和 3.10(从 3.2.9 开始)。我们 高度推荐 并且只正式支持每个系列的最新版本。

Django 3.2 新特性

自动 AppConfig 发现

大多数可插拔的应用程序在 apps.py 子模块中定义一个 AppConfig 子类。许多人在他们的 __init__.py 中定义了一个 default_app_config 的变量,指向这个类。

apps.py 子模块存在并定义了一个 AppConfig 子类时,Django 现在自动使用该配置,所以你可以删除 default_app_config

default_app_config 使得在 INSTALLED_APPS 中只需声明应用程序的路径(例如 'django.contrib.admin')而不是应用程序配置的路径(例如 'django.contrib.admin.apps.AdminConfig')。它的引入是为了向后兼容前者的风格,目的是将生态系统切换到后者,但这种切换并没有发生。

随着自动发现 AppConfigdefault_app_config 不再需要了。因此,它被废弃了。

详见 配置应用程序

自定义自动创建的主键的类型

当定义一个模型时,如果模型中没有字段被定义为 primary_key=True,则会添加一个隐式主键。这个隐式主键的类型现在可以通过 DEFAULT_AUTO_FIELD 设置和 AppConfig.default_auto_field 属性来控制。不再需要在所有模型中覆盖主键。

保持历史行为,DEFAULT_AUTO_FIELD 的默认值是 AutoField。从 3.2 开始,新项目在生成时,DEFAULT_AUTO_FIELD 设置为 BigAutoField。另外,新的应用程序生成时,AppConfig.default_auto_field 设置为 BigAutoField。在未来的 Django 版本中,DEFAULT_AUTO_FIELD 的默认值将被改为 BigAutoField

为了避免将来不需要的迁移,要么明确设置 DEFAULT_AUTO_FIELDAutoField

DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

或在每个应用的基础上进行配置:

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    default_auto_field = 'django.db.models.AutoField'
    name = 'my_app'

或在每个模型的基础上:

from django.db import models

class MyModel(models.Model):
    id = models.AutoField(primary_key=True)

由于预期默认值的变化,如果你没有明确设置 DEFAULT_AUTO_FIELD,系统检查将提供一个警告。

当改变 DEFAULT_AUTO_FIELD 的值时,目前不能生成现有的自动创建的表的主键的迁移。请参阅 DEFAULT_AUTO_FIELD 文档以了解迁移此类表的详情。

函数索引

新的 *expressions 的位置参数 Index() 能够在表达式和数据库函数上创建函数索引。例如:

from django.db import models
from django.db.models import F, Index, Value
from django.db.models.functions import Lower, Upper


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

    class Meta:
        indexes = [
            Index(
                Lower('first_name'),
                Upper('last_name').desc(),
                name='first_last_name_idx',
            ),
            Index(
                F('height') / (F('weight') + Value(5)),
                name='calc_idx',
            ),
        ]

函数索引是使用 Meta.indexes 选项添加到模型的。

pymemcache 支持

新的 django.core.cache.backends.memcached.PyMemcacheCache 缓存后端允许使用 pymemcache 库操作 memcached。pymemcache 需要 3.4.0 或更高版本。更多细节,请参见 Django 中的缓存文档

管理站点的新装饰器

新的 display() 装饰器允许轻松地为自定义显示函数添加选项,这些函数可以与 list_displayreadonly_fields 一起使用。

同样,新的 action() 装饰器允许轻松地将选项添加到可与 actions 一起使用的动作函数。

使用 @display 装饰器的好处是,现在可以在需要指定自定义方法的属性时使用 @property 装饰器。在此之前,有必要在为方法指定所需的属性后使用 property() 函数来代替。

使用装饰器的好处是这些选项更容易被发现,因为它们可以被代码编辑器中的补全工具所提示。它们仅仅是一种方便,并且仍然在幕后的函数上设置相同的属性。

次要特性

django.contrib.admin

  • ModelAdmin.search_fields 现在允许针对带空格的引号短语进行搜索。

  • 如果在管理中注册了目标模型,只读的相关字段现在被呈现为可浏览的链接。

  • 管理现在支持主题化,包括一个根据浏览器配置启用的暗色主题。更多细节见 主题化支持

  • ModelAdmin.autocomplete_fields 现在搜索一个相关模型时尊重 ForeignKey.to_fieldForeignKey.limit_choices_to

  • 管理现在安装了一个全局最终回退视图,将未经认证的用户重定向到登录页面,无论该 URL 是否有效。这可以防止潜在的模型枚举隐私问题。

    尽管不推荐,你可以将新的 AdminSite.final_catch_all_view 设置为 False 来禁用所有视图。

django.contrib.auth

  • PBKDF2 密码散列器的默认迭代次数从 216,000 次增加到 260,000 次。

  • Argon2 密码散列器的默认变量改为 Argon2id。memory_costparallelism 分别增加到 102,400 和 8,以符合 argon2-cffi 的默认值。

    增加 memory_cost 将所需的内存从 512KB 推到 100MB。这仍然是相当保守的,但在内存有限的环境中可能会导致问题。如果是这种情况,可以对现有的散列器进行子类化以覆盖默认值。

  • Argon2, MD5, PBKDF2, SHA-1 密码散列器的默认盐熵从 71 位增加到 128 位。

django.contrib.contenttypes

django.contrib.postgres

django.contrib.sitemaps

django.contrib.syndication

  • 新的 item_comments 钩子允许为每个 feed 项目指定一个评论 URL。

数据库后端

  • 第三方数据库后端现在可以使用新的 DatabaseFeatures.django_test_skipsdjango_test_expected_failures 属性在 Django 测试套件中跳过或标记为预期失败的测试。

装饰器

错误报告

  • 自定义 ExceptionReporter 子类现在可以定义 html_template_pathtext_template_path 属性来重写用于渲染异常报告的模板。

文件上传

表单

通用视图

管理命令

  • loaddata 现在支持存储在 XZ 档案(.xz)和 LZMA 档案(.lzma)中的固定数据。
  • dumpdata 现在可以压缩 bz2gzlzmaxz 格式的数据。
  • makemigrations 现在可以在没有数据库连接的情况下调用。在这种情况下,会跳过检查是否有一致的迁移历史。
  • BaseCommand.required_system_checks 现在支持指定一个标签列表。在所选标签中注册的系统检查将在执行命令前被检查出错误。在之前的版本中,所有的系统检查或者都不执行,或者都会被执行。
  • 更新了对 Windows 上彩色终端输出的支持。各种现代终端环境被自动检测到,在其他情况下启用支持的选项也被改进。更多细节见 语法着色

迁移

  • 新的 Operation.migration_name_fragment 属性允许提供一个文件名片段,该片段将被用来命名只包含该操作的迁移。
  • 迁移现在支持从 pathlibos.PathLike 实例中序列化纯路径和具体路径对象。

模型

  • 在 PostgreSQL 上支持 QuerySet.select_for_update() 的新的 no_key 参数,允许获得较弱的锁,不会阻止创建通过外键引用被锁定行的新行。
  • When() 表达式现在允许使用 condition 参数与 lookups
  • 新的 Index.includeUniqueConstraint.include 属性允许在 PostgreSQL 11+ 上创建覆盖索引和覆盖唯一约束。
  • 新的 UniqueConstraint.opclasses 属性允许设置 PostgreSQL 操作符类。
  • QuerySet.update() 方法现在尊重 MySQL 和 MariaDB 的 order_by() 子句。
  • FilteredRelation() 现在支持嵌套关系。
  • QuerySet.select_for_update()of 参数现在于 MySQL 8.0.1+ 版本中被允许。
  • Value() 表达式现在会根据其提供的 value 的类型自动将其 output_field 解析为适当的 Field 子类,适用于 boolbytesfloatintstrdatetime.datedatetime.datetimedatetime.timedatetime.timedeltadecimal.Decimaluuid.UUID 实例。因此,在使用 Value() 时,解析数据库函数和组合表达式的 output_field 现在可能会因混合类型而崩溃。在这种情况下,你将需要明确地设置 output_field
  • 新的 QuerySet.alias() 方法允许为表达式创建可重复使用的别名,这些表达式不需要被选择,但可用于过滤、排序,或作为复杂表达式的一部分。
  • 新的 Collate 函数允许通过指定的数据库排列方式进行过滤和排序。
  • 如果在 QuerySet.distinct() 中只指定了一个字段,QuerySet.in_bulk()field_name 参数现在可以接受不同的字段。
  • TruncDateTruncTime 数据库函数的新 tzinfo 参数允许截断特定时区的数据时间。
  • CharFieldTextField 新增的 db_collation 参数允许为字段设置一个数据库排序。
  • 添加了 Random 数据库函数。
  • 聚合函数F()OuterRef() 以及其他表达式现在允许使用变换。详情参见 Expressions can reference transforms
  • atomic() 的新参数 durable 保证在原子块中所做的更改将被提交,如果该块退出时没有错误。嵌套的原子块被标记为耐用,将引发一个 RuntimeError
  • 添加了 JSONObject 数据库函数。

分页

请求和响应

安全

序列化

  • 新的 JSONL 序列化器允许使用 JSON Lines 格式与 dumpdataloaddata。这对填充大型数据库很有用,因为数据是逐行加载到内存中的,而不是一次性加载。

信号

模板

测试

实用程序

  • django.utils.timesince.timesince()django.utils.timesince.timeuntil() 函数的新 depth 参数允许指定要返回的相邻时间单位的数量。

验证器

  • 内置的验证器现在包括提供的值在提出的 ValidationErrorparams 参数。这允许自定义错误信息使用 %(value)s 占位符。
  • ValidationError 相等运算符现在忽略了 messagesparams 的排序。

3.2 中向后不兼容的更改

数据库后端 API

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

  • 新的 DatabaseFeatures.introspected_field_types 属性取代了这些特性:
    • can_introspect_autofield
    • can_introspect_big_integer_field
    • can_introspect_binary_field
    • can_introspect_decimal_field
    • can_introspect_duration_field
    • can_introspect_ip_address_field
    • can_introspect_positive_integer_field
    • can_introspect_small_integer_field
    • can_introspect_time_field
    • introspected_big_auto_field_type
    • introspected_small_auto_field_type
    • introspected_boolean_field_type
  • 要启用对覆盖索引(Index.include)和覆盖唯一约束(UniqueConstraint.include)的支持,设置 DatabaseFeatures.supports_covering_indexesTrue
  • 第三方数据库后端必须实现对 CharFieldTextField 的列数据库校对的支持,或者将 DatabaseFeatures.supports_collation_on_charfieldDatabaseFeatures.supports_collation_on_textfield 设为 False。如果不支持非确定的排序,请将 supports_non_deterministic_collations 设为 False
  • DatabaseOperations.random_function_sql() 已被删除,改用新的 Random 数据库函数。
  • DatabaseOperations.date_trunc_sql()DatabaseOperations.time_trunc_sql() 现在接受可选的 tzname 参数,以便在特定的时区进行截断。
  • DatabaseClient.runshell() 现在可以从 DatabaseClient.settings_to_cmd_args_env() 方法中获得参数和带有环境变量的可选字典给底层命令行客户端。第三方数据库后端必须实现 DatabaseClient.settings_to_cmd_args_env() 或覆盖 DatabaseClient.runshell()
  • 第三方数据库后端必须实现对函数索引的支持(Index.expressions)或者将 DatabaseFeatures.supports_expression_indexes 设为 False。如果 COLLATE 不是 CREATE INDEX 语句的一部分,请将 DatabaseFeatures.collate_as_index_expression 设为 True

django.contrib.admin

  • 管理中的分页链接现在是 1 开头索引,而不是 0 开头索引,即第一页的查询字符串是 ?p=1,而不是 ?p=0
  • 新的管理全局回退视图将打破在管理 URL 之后路由并匹配管理 URL 前缀的 URL 模式。你可以调整你的 URL 排序,或者,如果有必要,将 AdminSite.final_catch_all_view 设置为 False,禁用全局回退视图。更多细节见 Django 3.2 新特性
  • 最小化的 JavaScript 文件不再包括在管理中。如果你需要这些文件被最小化,请考虑使用第三方应用程序或外部构建工具。与管理一起打包的已被最小化的 JavaScript 文件(例如 jquery.min.js)仍然包括在内。
  • ModelAdmin.prepopulated_fields 不再剥离英文停顿词,例如 'a''an'

django.contrib.gis

  • 移除对 PostGIS 2.2 的支持。
  • Oracle 后端现在在调整多边形(和包含多边形的几何体集合)的方向并将其保存到数据库之前克隆它们。它们不再是可原地变更的。如果你在模型被保存后使用多边形,你可能会注意到这一点。

丢弃了对 PostgreSQL 9.5 的支持

对 PostgreSQL 9.5 的上游支持在 2021 年 2 月结束。Django 3.2 支持 PostgreSQL 9.6 及以上版本。

丢弃了对 MySQL 5.6 的支持

对 MySQL 5.6 的上游支持在 2021 年 4 月结束。Django 3.2 支持 MySQL 5.7 及以上版本。

杂项

  • Django 现在支持非 pytz 时区,例如 Python 3.9+ 的 zoneinfo 模块及其向后移植版本。

  • 未记录的 SpatiaLiteOperations.proj4_version() 方法改名为 proj_version()

  • slugify() 现在可以删除前面和后面的破折号以及下划线。

  • The intcomma and intword template filters no longer depend on the USE_L10N setting.

  • 移除对 argon2-cffi < 19.1.0 的支持。

  • 当国际化被禁用(USE_I18N = False)和本地化被启用(USE_L10N = True)时,缓存键不再包括语言。在这样的配置下,升级到 Django 3.2 后,对任何以前的缓存值的第一次请求将是一次缓存丢失。

  • ForeignKey.validate() 现在使用 _base_manager 而不是 _default_manager 来检查相关实例是否存在。

  • 当一个应用程序在 apps.py 子模块中定义了一个 AppConfig 子类,Django 现在会自动使用这个配置,即使它没有用 default_app_config 启用。如果你需要防止这种行为,请在 AppConfig 子类中设置 default = False。更多细节见 Django 3.2 新特性

  • 实例化一个抽象模型现在会引发 TypeError

  • setup_databases() 的关键字参数现在是只能用关键字。

  • 删除了无文档的 django.utils.http.limited_parse_qsl() 函数。请使用 urllib.parse.parse_qsl() 代替。

  • django.test.utils.TestContextDecorator 现在使用 addCleanup() 所以在 setUp() 方法中注册的清理会在 TestContextDecorator.disable() 前被调用。

  • 当一个会话在并发请求中被销毁时,SessionMiddleware 现在会引发 SessionInterrupted 异常,而不是 SuspiciousOperation

  • django.db.models.Field 相等运算符现在可以正确区分跨模型的继承字段实例。此外,此类字段的排序现在也被定义了。

  • 未记录的 django.core.files.locks.lock() 函数现在在文件不能被锁定时返回 False,而不是引发 BlockingIOError

  • 密码重置机制现在在用户电子邮件改变时使令牌无效。

  • makemessages 命令不再处理使用 makemessages --locale 选项指定的无效 locale,如果它们包含连字符('-')。

  • django.contrib.auth.forms.ReadOnlyPasswordHashField 表单字段现在默认为 disabled。因此 UserChangeForm.clean_password() 不再需要返回初始值。

  • cache.get_many()get_or_set()has_key()incr()decr()incr_version()decr_version() 的缓存操作现在可以正确处理缓存中的 None,与其他值相同,而不是表现为键不存在。

    由于 python-memcached 的限制,以前的行为被保留在已废弃的 MemcachedCache 后端。

  • SQLite 的最小支持版本从 3.8.3 增加到 3.9.0。

  • CookieStorage 现在以 RFC 6265 兼容的格式存储信息。对使用旧格式的 cookie 的支持仍然保留到 Django 4.1。

  • asgiref 的最小支持版本从 3.2.10 提高到 3.3.2。

在 3.2 中被废弃的功能

杂项

  • TestCase.setUpTestData() 中,将不支持用 copy.deepcopy() 创建深度拷贝的对象分配给类属性的做法已被废弃。
  • BaseCommand.requires_system_checks 中使用一个布尔值已被废弃。使用 '__all__' 来代替 True,使用 [] (一个空列表)来代替 False
  • EmailValidatorwhitelist 参数和 domain_whitelist 属性已被废弃。使用 allowlist 代替 whitelistdomain_allowlist 代替 domain_whitelist。你可能需要在现有的迁移中重命名 whitelist
  • default_app_config 应用程序配置变量已被废弃,因为现在自动发现了 AppConfig。更多细节请参见 Django 3.2 新特性
  • TransactionTestCase.assertQuerysetEqual() 中与字符串值比较时自动调用 repr(),已被废弃。如果你需要以前的行为,明确设置 transformrepr
  • django.core.cache.backends.memcached.MemcachedCache 后端已被废弃,因为 python-memcached 有一些问题,而且似乎无人维护。使用 django.core.cache.backends.memcached.PyMemcacheCachedjango.core.cache.backends.memcached.PyLibMCCache 代替。
  • django.contrib.messages.storage.cookie.CookieStorage 使用的消息格式与旧版本的 Django 生成的格式不同。对旧格式的支持一直持续到 Django 4.1。