Django 4.0 版本发行说明¶
2021 年 12 月 7 日
欢迎使用 Django 4.0 !
这些发布说明涵盖了 新功能,以及从 Django 3.2 或更早版本升级时需要注意的一些 不向后兼容的变更。我们已经 开始了一些功能的弃用过程。
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Python 兼容性¶
Django 4.0 支持 Python 3.8、3.9 和 3.10。我们 强烈建议 并只官方支持每个系列的最新版本。
Django 3.2.x 系列是最后一个支持 Python 3.6 和 3.7 的版本。
Django 4.0 新特性¶
zoneinfo 默认时区实现¶
Python 标准库的 zoneinfo 现在是 Django 中默认的时区实现。
这是从使用 pytz 到使用 zoneinfo 迁移的下一步。Django 3.2 允许使用非 pytz 时区。Django 4.0 将 zoneinfo 作为默认实现。对于 pytz 的支持现在已经不推荐使用,并将在 Django 5.0 中移除。
zoneinfo 是自 Python 3.9 起的 Python 标准库的一部分。如果你正在使用 Python 3.8,那么 backports.zoneinfo 包会在安装 Django 时自动安装。
迁移到 zoneinfo 应该在很大程度上是透明的。选择当前时区、在表单和模板中将日期时间实例转换为当前时区,以及在 UTC 中进行的带时区日期时间的操作都不受影响。
然而,如果你正在使用非 UTC 时区,并使用 pytz 的 normalize() 和 localize() API,可能还涉及到 TIME_ZONE 设置,那么你需要审查你的代码,因为``pytz`` 和 zoneinfo 并不完全等同。
为了给这样的审核留出时间,过渡性的 USE_DEPRECATED_PYTZ 设置允许在 4.x 发布周期内继续使用 pytz。这个设置将在 Django 5.0 中移除。
此外,zoneinfo 的作者创建了一个名为 pytz_deprecation_shim 的包,可用于协助从 pytz 迁移。这个包提供了帮助你安全移除 pytz 的 shims,并有一个详细的 迁移指南,展示了如何切换到新的 zoneinfo API。
如果需要逐步更新路径,建议使用 pytz_deprecation_shim 和过渡性的 USE_DEPRECATED_PYTZ 设置。
函数式唯一约束¶
UniqueConstraint() 的新的 *expressions 位置参数允许在表达式和数据库函数上创建功能性的唯一约束。例如:
from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import Lower
class MyModel(models.Model):
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    class Meta:
        constraints = [
            UniqueConstraint(
                Lower("first_name"),
                Lower("last_name").desc(),
                name="first_last_name_unique",
            ),
        ]
功能性唯一约束是通过在模型中使用 Meta.constraints 选项来添加的。
scrypt 密码哈希器¶
新的 scrypt 密码哈希器 更安全,推荐使用,但它不是默认选项,因为它需要 OpenSSL 1.1+ 和更多内存。
Redis 缓存后端¶
新的 django.core.cache.backends.redis.RedisCache 缓存后端提供了内置的支持,用于使用 Redis 进行缓存。需要 redis-py 的版本为 3.0.0 或更高。更多详情请参阅 Django 中关于使用 Redis 进行缓存的 文档。
基于模板的表单渲染¶
Forms、Formsets 和 ErrorList 现在使用模板引擎进行渲染,以增强自定义功能。查看 Form 的新方法 render()、get_context() 和 template_name,以及关于 Formset 的 formset 渲染。
次要特性¶
django.contrib.admin¶
admin/base.html模板现在有一个新的块header,其中包含了管理站点的标题。新的
ModelAdmin.get_formset_kwargs()方法允许自定义传递给表单集构造函数的关键字参数。导航侧边栏现在有一个快速筛选工具栏。
新的上下文变量
model包含了每个模型的模型类,已添加到AdminSite.each_context()方法中。新的
ModelAdmin.search_help_text属性允许指定搜索框的描述性文本。InlineModelAdmin.verbose_name_plural属性现在会回退到InlineModelAdmin.verbose_name+'s'。jQuery 从版本 3.5.1 升级到 3.6.0 。
django.contrib.admindocs¶
admindocs 现在允许复杂的设置,其中
ROOT_URLCONF不是一个字符串。admindocs的模型部分现在显示缓存的属性。
django.contrib.auth¶
PBKDF2 密码哈希器的默认迭代次数从 260 , 000 增加到 320 , 000 。
新的
LoginView.next_page属性和get_default_redirect_url()方法允许自定义登录后的重定向。
django.contrib.gis¶
新增对 SpatiaLite 5 的支持。
GDALRaster现在允许在任何 GDAL 虚拟文件系统中创建栅格数据。新的
GISModelAdmin类允许自定义用于GeometryField的小部件,这是鼓励使用的,而不是不推荐使用的GeoModelAdmin和OSMGeoAdmin。
django.contrib.postgres¶
PostgreSQL 后端现在支持通过服务名称进行连接。更多详情请参阅 PostgreSQL 连接配置。
新的
AddConstraintNotValid操作允许在 PostgreSQL 上创建检查约束,而无需验证所有现有行是否满足新约束。新的
ValidateConstraint操作允许验证在 PostgreSQL 上使用AddConstraintNotValid创建的检查约束。新的
ArraySubquery()表达式允许在 PostgreSQL 上使用子查询来构建值列表。新的
trigram_word_similar查找以及TrigramWordDistance()和TrigramWordSimilarity()表达式允许使用 trigram 单词相似度。
django.contrib.staticfiles¶
ManifestStaticFilesStorage现在会将 JavaScript 源映射引用的路径替换为它们的哈希版本。ManifestFilesMixin和ManifestStaticFilesStorage的新参数manifest_storage允许自定义清单文件的存储。
缓存¶
django.core.cache.backends.base.BaseCache的新异步 API 开始了使缓存后端支持异步的过程。新的异步方法都有a前缀的名称,例如aadd()、aget()、aset()、aget_or_set()或adelete_many()。今后,
a前缀将用于一般方法的异步变体。
CSRF¶
CSRF 保护现在会查看是否存在
Origin标头。为了实现这一点,需要对CSRF_TRUSTED_ORIGINS设置进行 一些更改。
表单¶
ModelChoiceField现在会在引发invalid_choice错误消息的ValidationError中的params参数中包含提供的值,这允许自定义错误消息使用%(value)s占位符。BaseFormSet现在会在渲染非表单错误时添加一个额外的类nonform,以帮助区分它们与特定于表单的错误。BaseFormSet现在允许通过设置deletion_widget属性或覆盖get_deletion_widget()方法来自定义在通过can_delete删除表单时使用的小部件。
国际化¶
添加了对马来语的支持和翻译。
通用视图¶
DeleteView现在使用FormMixin,允许你提供一个Form的子类,例如带有复选框的表单,来确认删除。此外,这还允许DeleteView与django.contrib.messages.views.SuccessMessageMixin配合使用。根据
FormMixin,对于 POST 请求的对象删除是在form_valid()中处理的。如果需要,应将delete()处理程序中的自定义删除逻辑移动到form_valid()或共享的辅助方法中。
日志¶
现在,用于 SQL 调用的数据库的别名会作为额外的上下文与每条消息一起传递到 django.db.backends 记录器中。
管理命令¶
runserver管理命令现在支持--skip-checks选项。在 PostgreSQL 上,
dbshell现在支持指定密码文件。shell命令现在在启动时会尊重sys.__interactivehook__。这允许在交互式会话之间加载 shell 历史记录。因此,在 隔离 模式下运行时不再加载readline。新的
BaseCommand.suppressed_base_arguments属性允许在帮助输出中抑制不支持的默认命令选项。新的
startapp --exclude和startproject --exclude选项允许从模板中排除目录。
模型¶
新的
QuerySet.contains(obj)方法返回查询集是否包含给定对象。它尝试以最简单和最快的方式执行查询。Round()数据库函数的新precision参数允许指定舍入后的小数位数。使用 SQLite 3.35+ 时,
QuerySet.bulk_create()现在会为对象设置主键。DurationField现在在 SQLite 上支持乘法和除法以及标量值。QuerySet.bulk_update()现在会返回更新的对象数量。新的
Expression.empty_result_set_value属性允许在函数用于空结果集时指定要返回的值。在 MariaDB 10.6+ 上,现在允许使用
QuerySet.select_for_update()的skip_locked参数。Lookup表达式现在可以在QuerySet的注释、聚合和直接筛选中使用。内置聚合函数的新 default 参数允许指定当查询集(或分组)不包含条目时要返回的值,而不是返回
None。
请求和响应¶
SecurityMiddleware现在会添加具有值'same-origin'的 Cross-Origin Opener Policy 头,以防止跨源弹出窗口共享相同的浏览上下文。你可以通过将SECURE_CROSS_ORIGIN_OPENER_POLICY设置为None来阻止添加此头部。
信号¶
pre_migrate()和post_migrate()信号现在有一个新的stdout参数,允许将输出重定向到类似流的对象。在发出详细输出时,应优先考虑使用它,以便在测试时能够正确捕获输出,而不是使用sys.stdout和print()。
模板¶
模板过滤器
floatformat现在允许使用u后缀来强制禁用本地化。
测试¶
django.test.utils.setup_databases()的新参数serialized_aliases决定了哪些DATABASES别名的测试数据库应该被序列化以允许使用 serialized_rollback 特性。test --buffer选项现在支持并行测试。DiscoverRunner的新参数logger允许使用 Python logger 进行日志记录。新的
DiscoverRunner.log()方法提供了一种记录消息的方式,它使用DiscoverRunner.logger进行日志记录,如果未设置则打印到控制台。DiscoverRunner现在可以使用test --shuffle选项以随机顺序执行测试。test --parallel选项现在支持值auto,以为每个处理器核心运行一个测试进程。TestCase.captureOnCommitCallbacks()现在会捕获在执行transaction.on_commit()回调期间添加的新回调。
4.0 版本中不向后兼容的变更¶
数据库后端 API¶
本节介绍了第三方数据库后端可能需要的更改。
DatabaseOperations.year_lookup_bounds_for_date_field()和year_lookup_bounds_for_datetime_field()方法现在接受可选的iso_year参数,以支持 ISO-8601 周编号年份的范围。DatabaseSchemaEditor._unique_sql()和_create_unique_sql()方法的第二个参数现在是fields,而不再是columns。
django.contrib.gis¶
移除了对 PostGIS 2.3 的支持。
移除了对 GDAL 2.0 和 GEOS 3.5 的支持。
停止支持 PostgreSQL 9.6¶
PostgreSQL 9.6 的上游支持将在 2021 年 11 月结束。 Django 4.0 支持 PostgreSQL 10 及更高版本。
此外,psycopg2 的最低支持版本已从 2.5.4 提高到 2.8.4,因为 psycopg2 2.8.4 是第一个支持 Python 3.8 的版本。
停止支持 Oracle 12.2 和 18c¶
Oracle 12.2 的上游支持将于 2022 年 3 月结束,Oracle 18c 的上游支持将于 2021 年 6 月结束。 Django 3.2 将得到支持直至 2024 年 4 月。 Django 4.0 正式支持 Oracle 19c 。
CSRF_TRUSTED_ORIGINS 变更¶
格式变更¶
在 CSRF_TRUSTED_ORIGINS 设置中,值必须包括方案(例如,'http://' 或 'https://'),而不仅仅是主机名。
此外,以点开头的值现在必须在点之前加上一个星号。例如,将 '.example.com' 更改为 'https://*.example.com'。
系统检查会检测到任何所需的更改。
现在可能需要配置它¶
由于 CSRF 保护现在参考 Origin 标头,如果你通过将 CSRF_COOKIE_DOMAIN (或者如果启用了 CSRF_USE_SESSIONS,则为 SESSION_COOKIE_DOMAIN)设置为以点开头的值以允许来自子域的请求,你可能需要设置 CSRF_TRUSTED_ORIGINS。
SecurityMiddleware 不再设置 X-XSS-Protection 头¶
如果 SECURE_BROWSER_XSS_FILTER 设置为 True,则 SecurityMiddleware 不再设置 X-XSS-Protection 头。此设置已被移除。
大多数现代浏览器不再支持 X-XSS-Protection HTTP 头。你可以使用 Content-Security-Policy 来代替,但请不要允许 'unsafe-inline' 脚本。
如果您想要支持旧版浏览器并设置标头,请在自定义中间件中使用以下代码行:
response.headers.setdefault("X-XSS-Protection", "1; mode=block")
迁移自动检测器的更改¶
迁移自动检测器现在使用模型状态而不是模型类。此外,对于 ForeignKey 和 ManyToManyField 字段的迁移操作不再指定未在字段初始化期间传递的属性。
作为副作用,在某些情况下,运行 makemigrations 可能会为 ManyToManyField 和 ForeignKey 字段生成无操作的 AlterField 操作。
DeleteView 变更¶
DeleteView 现在使用 FormMixin 来处理 POST 请求。因此,任何在 delete() 处理程序中的自定义删除逻辑应该移动到 form_valid(),或者如果需要的话,可以移动到共享的辅助方法。
Oracle 上的表和列命名方案发生了变化。¶
Django 4.0 无意中更改了 Oracle 上的表和列命名方案。这会导致模型和字段的名称超过 30 个字符的错误。不幸的是,需要重命名一些 Oracle 表和列。请使用 33789 中的升级脚本生成 RENAME 语句来更改命名方案。
杂项¶
已移除对
cx_Oracle版本低于 7.0 的支持。为了允许在子路径上提供 Django 站点而不更改
STATIC_URL的值,现在在默认的startproject模板中从该设置中移除了前导斜杠(现在是'static/')。当直接访问
AdminSite的管理index视图时,不再使用never_cache进行装饰,而是建议通过AdminSite.urls属性或AdminSite.get_urls()方法访问。对切片的查询集执行不支持的操作现在会引发
TypeError而不是AssertionError。未记录的
django.test.runner.reorder_suite()函数已更名为reorder_tests()。现在它接受一个测试的可迭代对象而不是测试套件,并返回一个测试的迭代器。现在,如果使用空的
name调用FileSystemStorage.delete(),会引发ValueError而不是AssertionError。如果使用无效的
content或mimetype参数调用EmailMultiAlternatives.attach_alternative()或EmailMessage.attach(),现在会引发ValueError而不是AssertionError。assertHTMLEqual()不再将没有值的非布尔属性视为与具有相同名称和值的属性相等。现在,无法加载的测试,例如由于语法错误等原因,使用
test --tag时始终匹配。未记录的
django.contrib.admin.utils.lookup_needs_distinct()函数已更名为lookup_spawns_duplicates()。未记录的
HttpRequest.get_raw_uri()方法已被移除。HttpRequest.build_absolute_uri()方法可能是一个合适的替代方法。未记录的
ModelAdmin.log_addition()、log_change()和log_deletion()方法的object参数已更名为obj。NodeList.render()不再将单个节点的render()方法的输出转换为字符串。根据文档,Node.render()应始终返回一个字符串。django.db.models.sql.query.Query的where_class属性以及ForeignObject和ForeignObjectRel的私有方法get_extra_restriction()的where_class参数已被移除。如果需要,可以初始化django.db.models.sql.where.WhereNode。未记录的
Query.add_filter()方法的filter_clause参数被替换为两个位置参数filter_lhs和filter_rhs。CsrfViewMiddleware现在使用request.META['CSRF_COOKIE_NEEDS_UPDATE']代替request.META['CSRF_COOKIE_USED']、request.csrf_cookie_needs_reset和response.csrf_cookie_set来跟踪 CSRF cookie 是否应该发送。这是一个未记录的私有 API。未记录的
TRANSLATOR_COMMENT_MARK常量已从django.template.base移动到django.utils.translation.template。未记录的
django.db.migrations.state.ProjectState.__init__()方法的real_apps参数现在必须是一个集合(set),如果提供的话。RadioSelect和CheckboxSelectMultiple小部件现在在<div>标签中呈现,以便屏幕阅读器更简洁地宣读它们。如果需要以前的行为,请使用来自 Django 3.2 的适当模板 覆盖小部件模板。模板过滤器
floatformat不再依赖于USE_L10N设置,并始终返回本地化的输出。使用u后缀来禁用本地化。USE_L10N设置的默认值已更改为True。有关更多详细信息,请参阅上面的 本地化部分。作为 迁移到 zoneinfo 的一部分,
django.utils.timezone.utc被更改为别名datetime.timezone.utc。asgiref的最低支持版本已从 3.3.2 增加到 3.4.1。
在 4.0 版本中废弃的功能¶
使用 pytz 时区¶
作为 迁移到 zoneinfo 的一部分,不推荐使用 pytz 时区。
相应地,以下函数的 is_dst 参数也已被弃用:
在 Django 5.0 中将移除对 pytz 的支持。
时区支持¶
为了遵循良好的实践,USE_TZ 设置的默认值将从 False 更改为 True,并且在 Django 5.0 中将默认启用时区支持。
请注意,由 django-admin startproject 创建的默认 settings.py 文件自 Django 1.4 起就包括 USE_TZ = True。
你可以在那之前在项目设置中将 USE_TZ 设置为 False 以选择不使用时区支持。
本地化¶
为了遵循良好的实践,USE_L10N 设置的默认值从 False 更改为 True。
此外,从此版本开始,USE_L10N 已被弃用。从 Django 5.0 开始,默认情况下,Django 显示的任何日期或数字都将进行本地化。
Django 仍将支持 {% localize %} 标签以及 localize/ unlocalize 过滤器。
杂项¶
SERIALIZE测试设置已被弃用,因为可以从启用 serialized_rollback 选项的databases推断出。未记录的
django.utils.baseconv模块已被弃用。未记录的
django.utils.datetime_safe模块已被弃用。在 Django 5.0 中,构建在请求上下文之外的站点地图的默认协议将从
'http'更改为'https'。DiscoverRunner.build_suite()和DiscoverRunner.run_tests()的extra_tests参数已被弃用。在 Django 5.0 中,当没有行时,
ArrayAgg、JSONBAgg和StringAgg聚合将返回None,而不是分别返回[]、[]和''。如果需要以前的行为,请显式将default设置为Value([])、Value('[]')或Value('')。django.contrib.gis.admin.GeoModelAdmin和OSMGeoAdmin类已被弃用。请改为使用ModelAdmin和GISModelAdmin。由于表单渲染现在使用模板引擎,未记录的
BaseForm._html_output()辅助方法已被弃用。从
ErrorList和ErrorDict返回str的能力已被弃用。预期这些方法返回一个SafeString。
在 4.0 版本中移除的功能¶
这些功能已经完成了废弃周期,并在 Django 4.0 中被移除。
请参阅 在 3.0 中被废弃的功能 以获取有关这些更改的详细信息,包括如何删除对这些功能的使用。
django.utils.http.urlquote(),urlquote_plus(),urlunquote(), 和urlunquote_plus()已被移除。django.utils.encoding.force_text()和smart_text()已被移除。django.utils.translation.ugettext(),ugettext_lazy(),ugettext_noop(),ungettext(), 和ungettext_lazy()已被移除。django.views.i18n.set_language()不会在request.session中设置用户语言(键为_language)。alias=None在django.db.models.Expression.get_group_by_cols()子类的签名中是必需的。django.utils.text.unescape_entities()已被移除。django.utils.http.is_safe_url()已被移除。
请参阅 在 3.1 中被废弃的功能 以获取有关这些更改的详细信息,包括如何删除对这些功能的使用。
PASSWORD_RESET_TIMEOUT_DAYS设置已被移除。isnull查询不再允许使用非布尔值作为右侧的值。django.db.models.query_utils.InvalidQuery异常类已被移除。django-admin.py入口点已被移除。HttpRequest.is_ajax()方法已被移除。已移除对由
django.contrib.messages.storage.cookie.CookieStorage使用的 Django 3.1 之前版本的 cookie 值编码格式的支持。移除了对使用 SHA-1 哈希算法的 Django 3.1 之前版本密码重置令牌在管理站点的支持。
移除了对使用 Django 3.1 之前编码格式的会话的支持。
已移除对 Django 3.1 之前版本中使用 SHA-1 算法编码的
django.core.signing.Signer签名的支持。已移除在
django.core.signing.loads()中对 Django 3.1 之前版本中使用 SHA-1 算法编码的django.core.signing.dumps()签名的支持。移除了对使用 SHA-1 算法的 Django 3.1 之前用户会话的支持。
django.utils.deprecation.MiddlewareMixin.__init__()的get_response参数是必需的,并且不接受None。django.dispatch.Signal的providing_args参数已被移除。django.utils.crypto.get_random_string()的length参数是必需的。ModelMultipleChoiceField的list消息已被移除。不再支持将原始列别名传递给
QuerySet.order_by()。NullBooleanField模型字段已被移除,除了在历史迁移中的支持。django.conf.urls.url()已被移除。django.contrib.postgres.fields.JSONField模型字段已被移除,除了在历史迁移中的支持。django.contrib.postgres.fields.jsonb.KeyTransform和django.contrib.postgres.fields.jsonb.KeyTextTransform已被移除。django.contrib.postgres.forms.JSONField已被移除。{% ifequal %}和{% ifnotequal %}模板标签已被移除。DEFAULT_HASHING_ALGORITHM过渡设置已被移除。