Django 4.2 版本发行说明¶
2023 年 4 月 3 日
欢迎使用 Django 4.2 !
这些发布说明涵盖了 新功能,以及一些 不向后兼容的更改,在从 Django 4.1 或更早版本升级时需要注意。我们已经 开始了一些功能的弃用过程。
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Django 4.2 被指定为 长期支持版本。它将在发布后至少三年内接收安全更新。对于之前的 LTS 版本 Django 3.2,支持将在 2024 年 4 月结束。
Python 兼容性¶
Django 4.2 支持 Python 3.8、3.9、3.10、3.11 和 3.12(截止到 4.2.8 版本)。我们 强烈推荐 并且只官方支持每个系列的最新版本。
Django 4.2 新特性¶
Psycopg 3 支持¶
Django 现在支持 psycopg 版本 3.1.8 或更高版本。要更新您的代码,请安装 psycopg library,您不需要更改 ENGINE
,因为 django.db.backends.postgresql
支持这两个库。
对 psycopg2
的支持可能会在将来的某个时候被弃用并移除。
请注意,psycopg
3 对 psycopg2
进行了一些不兼容的更改。因此,您可能需要进行一些更改以适应与 psycopg2 的不同之处。
对列和表的注释¶
新的 Field.db_comment
和 Meta.db_table_comment
选项允许分别在列和表上创建注释。例如:
from django.db import models
class Question(models.Model):
text = models.TextField(db_comment="Poll question")
pub_date = models.DateTimeField(
db_comment="Date and time when the question was published",
)
class Meta:
db_table_comment = "Poll questions"
class Answer(models.Model):
question = models.ForeignKey(
Question,
on_delete=models.CASCADE,
db_comment="Reference to a question",
)
answer = models.TextField(db_comment="Question answer")
class Meta:
db_table_comment = "Question answers"
此外,新的 AlterModelTableComment
操作允许更改在 Meta.db_table_comment
中定义的表注释。
对 BREACH 攻击的缓解措施¶
GZipMiddleware
现在包括对 BREACH 攻击的缓解措施。它将在 gzip 响应中添加最多 100 个随机字节,以增加 BREACH 攻击的难度。在 Heal The Breach (HTB) paper 中详细了解有关缓解技术。
内存中的文件存储¶
新的 django.core.files.storage.InMemoryStorage
类提供了非持久性存储,对于加速测试并避免磁盘访问非常有用。
自定义文件存储¶
新的 STORAGES
设置允许配置多个自定义文件存储后端。它还控制了管理 文件 ("default"
键)和 静态文件 ("staticfiles"
键)的存储引擎。
在此版本中,旧的 DEFAULT_FILE_STORAGE
和 STATICFILES_STORAGE
设置已被弃用。
次要特性¶
django.contrib.admin
¶
现在可以在用户界面中切换管理界面的明亮或暗色主题,并且还可以设置为跟随系统设置。
管理界面现在更倾向于使用系统 UI 字体,不再需要下载字体。此外,提供了 CSS 变量,以便更轻松地覆盖默认字体系列。
admin/delete_confirmation.html 模板现在具有一些额外的块和脚本钩子,以便于定制。
filter_horizontal
和filter_vertical
组件的选择选项现在是可过滤的。模板
admin/base.html
现在具有一个新的块nav-breadcrumbs
,其中包含导航标志和breadcrumbs
块。ModelAdmin.list_editable
现在在进行编辑时使用原子事务。jQuery 的版本已从 3.6.0 升级到 3.6.4 。
django.contrib.auth
¶
PBKDF2 密码哈希器的默认迭代次数从 390 , 000 增加到 600 , 000 。
UserCreationForm
现在保存了自定义用户模型的多对多表单字段。新的
BaseUserCreationForm
现在是自定义用户创建表单的推荐基类。
django.contrib.gis
¶
GeoJSON 序列化程序 现在输出序列化要素的
id
键,默认为对象的主键。GDALRaster
类现在支持pathlib.Path
。GeoIP2
类现在支持从 DB-IP 下载的.mmdb
文件。OpenLayers 模板小部件不再包含内联 CSS(也删除了以前的
map_css
块),以更好地符合严格的内容安全策略。OpenLayersWidget
现在基于 OpenLayers 7.2.2(之前是 4.6.5)。新的
FromWKB()
和FromWKT()
函数允许从 Well-known binary (WKB) 和 Well-known text (WKT) 表示中创建几何图形。
django.contrib.postgres
¶
新的
trigram_strict_word_similar
查找以及TrigramStrictWordSimilarity()
和TrigramStrictWordDistance()
表达式允许使用 trigram 严格单词相似性。arrayfield.overlap
查找现在支持QuerySet.values()
和values_list()
作为右侧。
django.contrib.sitemaps
¶
新的
Sitemap.get_languages_for_item()
方法允许自定义显示项目的语言列表。
django.contrib.staticfiles
¶
ManifestStaticFilesStorage
现在具有实验性支持,在import
和export
语句中用其哈希值替换 JavaScript 模块的路径。如果你想尝试它,可以子类化ManifestStaticFilesStorage
并将support_js_module_import_aggregation
属性设置为True
。新的
ManifestStaticFilesStorage.manifest_hash
属性提供了对清单中所有文件的哈希,并在其中任何文件更改时更改。
数据库后端¶
错误报告¶
表单¶
ModelForm
现在接受新的Meta
选项formfield_callback
,以自定义表单字段。modelform_factory()
现在尊重表单的Meta
中的formfield_callback
属性。
国际化¶
增加了对中央库尔德语(索拉尼方言)的支持和翻译。
日志¶
django.db.backends 记录器现在以
DEBUG
级别记录事务管理查询(BEGIN
、COMMIT
和ROLLBACK
)。
管理命令¶
makemessages
命令现在支持具有私有子标记的区域设置,例如nl_NL-x-informal
。新的
makemigrations --update
选项将模型更改合并到最新的迁移中,并优化生成的操作。
迁移¶
迁移现在支持对
enum.Flag
对象的序列化。
模型¶
QuerySet
现在在除执行聚合时的窗口函数的析取过滤查询外,广泛支持与 窗口函数 进行过滤。prefetch_related()
现在支持带有切片查询集的Prefetch
对象。新的
robust
参数用于on_commit()
,允许在数据库事务成功提交后执行可能失败的操作。Now
现在在 MySQL 上支持微秒精度,在 SQLite 上支持毫秒精度。F()
表达式输出的BooleanField
现在可以使用~F()
(取反操作符)进行取反。Model
现在提供了一些使用数据库的方法的异步版本,使用a
前缀:adelete()
、arefresh_from_db()
和asave()
。Related 管理器现在提供了一些更改相关对象集合的异步方法,使用
a
前缀:aadd()
、aclear()
、aremove()
和aset()
。CharField.max_length
不再需要在 PostgreSQL 上设置,因为它支持无限长度的VARCHAR
列。
请求和响应¶
StreamingHttpResponse
现在在通过 ASGI 提供服务时支持异步迭代器。
测试¶
test --debug-sql
选项现在使用sqlparse
格式化 SQL 查询。RequestFactory
、AsyncRequestFactory
、Client
和AsyncClient
类现在支持headers
参数,它接受一个包含头部名称和值的字典。这允许更自然的语法来声明头部。# Before: self.client.get("/home/", HTTP_ACCEPT_LANGUAGE="fr") await self.async_client.get("/home/", ACCEPT_LANGUAGE="fr") # After: self.client.get("/home/", headers={"accept-language": "fr"}) await self.async_client.get("/home/", headers={"accept-language": "fr"})
实用程序¶
django.utils.html.json_script()
函数的新参数encoder
允许自定义 JSON 编码器类。私有的内部 vendored 版本的
urllib.parse.urlsplit()
现在会删除'\r'
、'\n'
和'\t'
(参见 CVE-2022-0391 和 bpo-43882)。这是为了保护可能错误使用内部url_has_allowed_host_and_scheme()
函数而不是使用文档中记录的处理 URL 重定向的函数的项目。Django 的函数没有受到影响。新的
django.utils.http.content_disposition_header()
函数返回根据 RFC 6266 规定的Content-Disposition
HTTP 标头值。
验证器¶
CommonPasswordValidator
使用的常见密码列表已更新为最新版本。
Django 4.2 中的不向后兼容的变更¶
数据库后端 API¶
本节介绍了第三方数据库后端可能需要的更改。
DatabaseFeatures.allows_group_by_pk
已被移除,因为它仅保留以适应一个已被 MySQL 5.7.15 中正确的功能依赖检测所取代的 MySQL 扩展。请注意,仍然支持DatabaseFeatures.allows_group_by_selected_pks
,如果您的后端支持GROUP BY
子句中的功能依赖检测,应该启用它,如SQL:1999
标准所规定的。inspectdb
现在使用DatabaseIntrospection.get_table_description()
中的display_size
,而不是internal_size
用于CharField
。
不再支持 MariaDB 10.3¶
MariaDB 10.3 的上游支持将于 2023 年 5 月结束。 Django 4.2 支持 MariaDB 10.4 及更高版本。
不再支持 MySQL 5.7¶
MySQL 5.7 的上游支持将于 2023 年 10 月结束。 Django 4.2 支持 MySQL 8 及更高版本。
不再支持 PostgreSQL 11¶
PostgreSQL 11 的上游支持将于 2023 年 11 月结束。 Django 4.2 支持 PostgreSQL 12 及更高版本。
在 Model.save()
中设置 update_fields
可能现在是必需的¶
为了避免更新不必要的列,QuerySet.update_or_create()
现在将 update_fields
传递给 Model.save()
调用。因此,在调用 super()
之前,应该将在自定义的 save()
方法中修改的任何字段添加到 update_fields
关键字参数中。详细信息请参阅 重写之前定义的模型方法。
在 MySQL 上取消了对原始聚合的支持¶
MySQL 8+ 允许在 GROUP BY
列上使用函数依赖,因此在 Django 4.2 之前的版本中通过对主表的主键进行分组的解决方法已被移除。因此,在 MySQL 上不再支持使用 RawSQL()
进行聚合,因为无法确定这些聚合是否在 GROUP BY
子句中需要或有效。请改用 聚合函数。
杂项¶
未记录的
django.http.multipartparser.parse_header()
函数已被移除。请改用django.utils.http.parse_header_parameters()
。{% blocktranslate asvar … %}
的结果现在被标记为适用于(HTML)输出目的的安全内容。在管理界面的搜索框中移除了
autofocus
HTML 属性,因为它对屏幕阅读器可能会造成困惑。makemigrations --check
选项不再创建缺失的迁移文件。Expression.get_group_by_cols()
的alias
参数已被移除。sqlparse
的最低支持版本已从 0.2.2 增加到 0.3.1。Exists
表达式的未记录的negated
参数已被移除。未记录的
Query.add_annotation()
方法的is_summary
参数已被移除。最低支持的 SQLite 版本从 3.9.0 提高到 3.21.0 。
asgiref
的最低支持版本已从 3.5.2 增加到 3.6.0。UserCreationForm
现在拒绝仅在大小写上不同的用户名。如果需要之前的行为,请改用BaseUserCreationForm
。mysqlclient
的最低支持版本从 1.4.0 增加到 1.4.3。argon2-cffi
的最低支持版本已从 19.1.0 增加到 19.2.0。Pillow
的最低支持版本已从 6.2.0 增加到 6.2.1。jinja2
的最低支持版本已从 2.9.2 增加到 2.11.0。redis-py 的最低支持版本已从 3.0.0 增加到 3.4.0。
手动实例化的
WSGIRequest
对象必须为wsgi.input
提供一个类似文件的对象。之前,Django 对于 WSGI 规范中指定的预期行为更加宽松。已移除对
PROJ
版本低于 5 的支持。EmailBackend
现在验证hostname
和certificates
。如果你需要以前不那么严格且不推荐的行为,可以子类化EmailBackend
并重写ssl_context
属性。
在 4.2 版本中弃用的功能¶
index_together
选项已被弃用,推荐使用 indexes
¶
The Meta.index_together
option is deprecated in favor of the
indexes
option.
迁移现有的 index_together
应该作为一个迁移来处理。例如:
class Author(models.Model):
rank = models.IntegerField()
name = models.CharField(max_length=30)
class Meta:
index_together = [["rank", "name"]]
应该变成:
class Author(models.Model):
rank = models.IntegerField()
name = models.CharField(max_length=30)
class Meta:
indexes = [models.Index(fields=["rank", "name"])]
运行 makemigrations
命令将生成一个迁移,其中包含一个 RenameIndex
操作,用于重命名现有的索引。接下来,考虑合并迁移以从历史迁移中移除 index_together
。
AlterIndexTogether
迁移操作现在官方上仅支持用于 Django 4.2 之前的迁移文件。出于向后兼容性的原因,它仍然是公共 API 的一部分,没有计划弃用或移除它,但不应该在新的迁移中使用。应该使用 AddIndex
和 RemoveIndex
操作代替。
传递编码的 JSON 字符串文字给 JSONField
已被弃用¶
JSONField
及其相关的查找和聚合操作曾允许传递 JSON 编码的字符串文字,这导致了在数据库后端的角度上对字符串文字是否已经编码的歧义。
在弃用期间,将尝试对字符串字面值进行 JSON 解码,并在成功时发出警告,指出应传递非编码形式的内容。
曾经用于传递 JSON 编码的字符串文字的代码:
Document.objects.bulk_create(
Document(data=Value("null")),
Document(data=Value("[]")),
Document(data=Value('"foo-bar"')),
)
Document.objects.annotate(
JSONBAgg("field", default=Value("[]")),
)
应该变成:
Document.objects.bulk_create(
Document(data=Value(None, JSONField())),
Document(data=[]),
Document(data="foo-bar"),
)
Document.objects.annotate(
JSONBAgg("field", default=[]),
)
从 Django 5.1+ 开始,字符串字面值将被隐式解释为 JSON 字符串字面值。
杂项¶
BaseUserManager.make_random_password()
方法已被弃用。请参阅 Python 的 secrets 模块的文档 了解如何使用 Python 的secrets
模块生成密码的示例和最佳实践。length_is
模板过滤器已被弃用,推荐使用length
和在{% if %}
标签内使用==
运算符。例如:{% if value|length == 4 %}…{% endif %} {% if value|length == 4 %}True{% else %}False{% endif %}
而不是:
{% if value|length_is:4 %}…{% endif %} {{ value|length_is:4 }}
django.contrib.auth.hashers.SHA1PasswordHasher
、django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher
和django.contrib.auth.hashers.UnsaltedMD5PasswordHasher
已被弃用。django.contrib.postgres.fields.CICharField
已被弃用,推荐使用CharField(db_collation="…")
,并指定一个不区分大小写的非确定性排序规则(collation)。django.contrib.postgres.fields.CIEmailField
已被弃用,推荐使用EmailField(db_collation="…")
,并指定一个不区分大小写的非确定性排序规则(collation)。django.contrib.postgres.fields.CITextField
已被弃用,推荐使用TextField(db_collation="…")
,并指定一个不区分大小写的非确定性排序规则(collation)。django.contrib.postgres.fields.CIText
mixin 已被弃用。BaseGeometryWidget
的map_height
和map_width
属性已被弃用,请改用 CSS 来设置地图小部件的大小。SimpleTestCase.assertFormsetError()
已被弃用,推荐使用assertFormSetError()
。TransactionTestCase.assertQuerysetEqual()
已被弃用,推荐使用assertQuerySetEqual()
。将位置参数传递给
Signer
和TimestampSigner
已被弃用,推荐使用仅限关键字的参数。DEFAULT_FILE_STORAGE
设置已被弃用,推荐使用STORAGES["default"]
。STATICFILES_STORAGE
设置已被弃用,推荐使用STORAGES["staticfiles"]
。django.core.files.storage.get_storage_class()
函数已被弃用。