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_Oracle7.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临时配置。


