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 特性。 - Django 测试运行器现在在并行测试中支持 --buffer 选项。
- DiscoverRunner 的新参数
logger
允许使用 Python logger 进行日志记录。 - 新的 DiscoverRunner.log() 方法提供了一种记录消息的方式,它使用
DiscoverRunner.logger
进行日志记录,如果未设置则打印到控制台。 - Django 测试运行器现在支持 --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
。 - RssFeed、Atom1Feed 及其子类现在将没有内容的元素作为自关闭标签进行输出。
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.db.models.query.QuerySet.datetimes()
- 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.utils.timezone.make_aware()
在 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
过渡设置已被移除。