2021 年 12 月 7 日
欢迎使用 Django 4.0 !
这些发布说明涵盖了 新功能,以及从 Django 3.2 或更早版本升级时需要注意的一些 不向后兼容的变更。我们已经 开始了一些功能的弃用过程。
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Django 4.0 支持 Python 3.8、3.9 和 3.10。我们 强烈建议 并只官方支持每个系列的最新版本。
Django 3.2.x 系列是最后一个支持 Python 3.6 和 3.7 的版本。
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+ 和更多内存。
新的 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 保护现在会查看是否存在 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() 回调期间添加的新回调。
本节介绍了第三方数据库后端可能需要的更改。
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 的上游支持将在 2021 年 11 月结束。 Django 4.0 支持 PostgreSQL 10 及更高版本。
此外,psycopg2 的最低支持版本已从 2.5.4 提高到 2.8.4,因为 psycopg2 2.8.4 是第一个支持 Python 3.8 的版本。
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(),或者如果需要的话,可以移动到共享的辅助方法。
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。
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。
这些功能已经完成了废弃周期,并在 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 过渡设置已被移除。
8月 13, 2025