2021年12月7日,Django 团队正式发布了 Django 4.0。主要新增功能有:
- 新增RedisCache后台缓存提供对 Redis 缓存的内置支持。
- 为减化对Forms, Formsets和ErrorList的自定义,现在可通过模板引擎对它们进行渲染。
- Python标准库中的zoneinfo成为当前 Django 中对时区的默认实现。
安装方式:
1 2 3 4 |
pip install Django==4.0 git clone https://github.com/django/django.git # 下载 https://github.com/django/django/archive/main.tar.gz |
4.0的发布也意味着3.2成为了LTS 版本,3.2的安全问题修复将持续至2024年4月,所以大可不必着急在生产上升级版本。但使用Django 3.1的朋友就要注意了,因为该版本已终止了官方维护,请尽快升级至3.2。
Django 4.0版本有以下值得注意的地方:
Python兼容性
Django 4.0兼容Python 3.8, 3.9和3.10。强烈建议使用这些版本的最新官方发行包。这也意味着Django 3.2.x系列是对Python 3.6 和 3.7进行支持的最后一版 Django。
Django 4.0的新特性
zoneinfo
成为默认时区实现
Python标准库中的zoneinfo
目前成为了 Django 对时区的默认实现。
使用zoneinfo
是对迁移pytz
的更进一步实现。Django 3.2中允许使用非pytz
时区,Django 4.0则让 zoneinfo
成为了默认实现。对pytz
的支持已降级并且在Django 5.0中会彻底移除。
zoneinfo
自Python 3.9加入了Python的标准库。使用Python 3.8就会在安装 Django 时自动安装 backports.zoneinfo
包。
采用 zoneinfo
大多地方都是显而易见的。 对当前时区的选择、在表单和模板中将datetime实例转化当前时区以及UTC时间的操作均不受影响。
但如果使用的是非UTC时区,配置了TIME_ZONE
以及及使用了 pytz
normalize()
和 localize()
API的话,则需要审计下代码,因为pytz
和 zoneinfo
并非完全一致。
为了对于这类审计保留时间,临时使用 USE_DEPRECATED_PYTZ
设置可允许在4.x 中继续使用 pytz
。但这一设置会在Django 5.0中移除。
此外,zoneinfo
作者创建的pytz_deprecation_shim 包,也可用于辅助对pytz
的迁移。这个包提供了一个 shim 辅助用户安全地移除掉 pytz
,并且提供了详细的迁移指南 讲解如何迁移至新的 zoneinfo
API。
如果采用渐进升级策略,建议使用 pytz_deprecation_shim 和 USE_DEPRECATED_PYTZ
临时配置。
Functional unique constraints
UniqueConstraint()
中新的 *expressions
位置参数让我们可以用表达式及数据库函数创建唯一性约束。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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密码哈希工具 更加案例,也是PBKDF2加密算法中所推荐使用中。但它并非默认工具,因为要求使用OpenSSL 1.1+版本同时也更耗内存。
Redis后端缓存
新的django.core.cache.backends.redis.RedisCache
后端缓存提供了对 Redia 缓存的内置支持。要求使用redis-py 3.0.0或更高版本。更多详情,请参见在Django中使用 Redis 进行缓存的相关文档。
表单的模板渲染
Forms
, Formsets和 ErrorList
现在使用模板引擎来改善其自定义特性。参见 Form
的新API render()
, get_context()
和 template_name
以及 Formset
的formset渲染。
小功能修改
django.contrib.admin
admin/base.html
模板中新增了一个header
代码块,包含有管理后台的头部。- 新的
ModelAdmin.get_formset_kwargs()
方法允许向formset构造函数传递自定义关键词参数。 - 侧边栏导航现在拥有一个快速过滤工具栏。
- 新增上下文变量
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
操作支持通过AddConstraintNotValid
创建的PostgreSQL约束的校验。 - 新的
ArraySubquery()
表达式支持对PostgreSQL使用子查询构建值列表。 - 新的
trigram_word_similar
查询和TrigramWordDistance()
及TrigramWordSimilarity()
表达式支持三元词相似度搜索。
django.contrib.staticfiles
ManifestStaticFilesStorage
使用JavaScript source map路径哈希值替换了原来的路径。-
ManifestFilesMixin
和ManifestStaticFilesStorage
的新参数manifest_storage
可用于自定义声明文件存储。
缓存
-
django.core.cache.backends.base.BaseCache
的新async API开始让后端缓存操作兼容异步。新的异步方法都带有a
作为前缀,如aadd()
、aget()
、aset()
、aget_or_set()
或adelete_many()
。推而广之,前缀
a
通常用于方法的异步变体。
CSRF
- CSRF跨站保护在
Origin
头存在时会使用到它。要使用这一功能,需要就CSRF_TRUSTED_ORIGINS
的配置做一些修改。
Forms
ModelChoiceField
包含了invalid_choice
错误消息中所抛出ValidationError
的params
参数。这样我们可以在自定义错误消息中使用%(value)s
占位符。BaseFormSet
使用一个额外的nonform
类来渲染非表单错误,有助于与表单相关错误进行区分。BaseFormSet
通过can_delete
可以设置删除表单时的自定义组件,配置方式为deletion_widget
属性或重载get_deletion_widget()
方法。
国际化
- 新增了对马来语的支持和翻译。
通用视图
-
DeleteView
现在使用FormMixin
,可由我们提供一个比如带有复选框的Form
子类 ,来确认删除。此外,这会让DeleteView
可与django.contrib.messages.views.SuccessMessageMixin
配合使用。对应
FormMixin
, POST请求的对象删除在form_valid()
中进行处理。delete()
handler中的自定义删除逻辑应迁移至form_valid()
或按需移至一个共用帮助方法中。
日志
- SQL调用中使用的数据库别名可与消息一起由附加的上下文传递给 django.db.backends 日志工具。
管理合集
runserver
管理命令支持--skip-checks
选项。- 对PostgreSQL,
dbshell
支持了指定密码文件。 shell
命令当前在启动时会调用sys.__interactivehook__
。这样可以在交互式会话间加载shell历史记录。因而在以isolated模式运行时就再加载readline
。- 新属性
BaseCommand.suppressed_base_arguments
允许在帮助输出中去除不支持的默认命令。 - 新选项
startapp --exclude
和startproject --exclude
允许从模板中排除掉某些目录。
模型
- 新方法
QuerySet.contains(obj)
返回queryset中是否包含指定对象。旨在尝试让查询变得尽可能简单、快捷。 Round()
数据函数的新参数precision
可指定四舍五入之后的小数位数。QuerySet.bulk_create()
在SQLite 3.35+版本时为对象设置主键。DurationField
支持对SQLite中的标量值进行乘除。QuerySet.bulk_update()
返回更新了的对象数。- 新属性
Expression.empty_result_set_value
支持在对空结果集执行函数时返回的值。 - 支持在MariaDB 10.6+版本中对
QuerySet.select_for_update()
使用skip_locked
参数。 - 支持在
QuerySet
注解、聚合运算和过滤器中直接使用Lookup
表达式。 - 内置聚合运算新增 default 参数,可以指定queryset(或分组)不包含内容时返回某个值,替换掉
None
。
请求和响应
SecurityMiddleware
添加了 Cross-Origin Opener Policy 头,值'same-origin'
可防止跨域弹窗暴露浏览上下文信息。可通过将SECURE_CROSS_ORIGIN_OPENER_POLICY
设置为None
来禁用对这个头信息的添加。
信号
pre_migrate()
和post_migrate()
信号的stdout
参数支持将输出重定向至流式对象。在发送长输出信息应优先于sys.stdout
和print()
使用,这样在测试时可进行更好的捕获。
模板
floatformat
模板过滤器支持使用u
后缀强制关闭本地化。
测试
django.test.utils.setup_databases()
的新参数serialized_aliases
指定测试数据库允许哪些数据库别名使用serialized_rollback 特性来序列化状态。- Django的测试运行器在并行测试中支持了
--buffer
选项。 DiscoverRunner
的新参数logger
支持使用Python logger 来记录日志。- 新的
DiscoverRunner.log()
方法提供了一种使用DiscoverRunner.logger
记录消息的方式,在没设置时在控制台中进行打印。 - Django测试运行器当前支持
--shuffle
选项,用于以随机顺序执行测试。 test --parallel
选项支持auto
值,用于为每个处理器核心运行一个进程。- 现在在执行
transaction.on_commit()
回调时TestCase.captureOnCommitCallbacks()
会捕获新增的回调。
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()
方法现在是字段
,不再是列
。
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及更高版本。
移除对Oracle 12.2 和 18c的支持
Oracle 12.2的上游支持于2022年终结,而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_TRUSTED_ORIGINS
,尤其是在允许子域进行请求时,方式为设置 CSRF_COOKIE_DOMAIN
(或在开启CSRF_USE_SESSIONS
时设置SESSION_COOKIE_DOMAIN
) 为一个以点号开头的值。
SecurityMiddleware
不再设置X-XSS-Protection
头
在设置SECURE_BROWSER_XSS_FILTER
为 True
时SecurityMiddleware
不再设置X-XSS-Protection
头。 该设置已被移除。
大部分现代浏览器不使用X-XSS-Protection
HTTP头。可以使用Content-Security-Policy 并不允许使用 'unsafe-inline'
脚本。
如果希望兼容老浏览器、设置这个头,可使用如下的自定义中间件:
1 |
<span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s1">'X-XSS-Protection'</span><span class="p">,</span> <span class="s1">'1; mode=block'</span><span class="p">)</span> |
Migration自动检测的调整
migration的autodetector使用模型状态取代模型类。同时对 ForeignKey
和 ManyToManyField
字段的迁移操作不再指定初始化阶段不传入这些字段的属性。
负面效应是在某些情况下,对 ManyToManyField
和 ForeignKey
字段运行makemigrations
时可能会生成无操作的AlterField
。
DeleteView
的调整
DeleteView
现在使用 FormMixin
来处理POST 请求。因此 delete()
handler中的所有自定义删除逻辑都应迁移至 form_valid()
或是共享帮助方法中。
其它
- 删除对
cx_Oracle
7.0以下版本的支持。 - 支持通过子路径访问Django站点而无需修改
STATIC_URL
,在默认的startproject
模板中也去除了前置斜线的设置 (当前为'static/'
)。 - 后台
index
视图的AdminSite
方法在直接访问时不再使用never_cache
进行装饰,无需使用原来推荐的AdminSite.urls
属性或AdminSite.get_urls()
方法。 - 对queryset切片所不支持的操作会抛出
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。这是一个记录在文档中的私有API。- 未放入文档的
TRANSLATOR_COMMENT_MARK
常量由django.template.base
迁移至django.utils.translation.template
。 - 未入文档的
django.db.migrations.state.ProjectState.__init__()
方法的参数real_apps
在提供时必须要设置。 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
测试已淘汰,因为可通过在databases
中启用 serialized_rollback选项来进行推导。- 淘汰未入文档的
django.utils.baseconv
模块。 - 淘汰未入文档的
django.utils.datetime_safe
模块。 - 请求上下文外构建网站地图的默认 sitemap协议将在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
)中的用户语言。- 在
django.db.models.Expression.get_group_by_cols()
子类签名中必须包含alias=None
。 - 删除
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 3.1之前
django.contrib.messages.storage.cookie.CookieStorage
所使用的cookie值编码格式的支持。 - 删除了对Django 3.1版本前后台站点密码重置token的支持(使用的是 SHA-1 哈希算法) 。
- 删除了对Django 3.1版本之前会话编码格式的支持。
- 删除了对Django 3.1版本之前
django.core.signing.Signer
签名的支持(以SHA-1进行编码)。 - 删除了Django 3.1版本之前
django.core.signing.loads()
中django.core.signing.dumps()
签名的支持(以SHA-1进行编码)。 - 删除了对Django 3.1之前(使用SHA-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
临时配置。