Django 4.2发行说明

April 3, 2023

欢迎来到Django 4.2!

这些发行说明涵盖 new features ,以及一些 backwards incompatible changes 在从Django 4.1或更早版本升级时,您需要注意这一点。我们已经 begun the deprecation process for some features

请参阅 如何将Django升级到更新版本 如果您要更新现有项目,请提供指南。

Django 4.2被指定为 long-term support release 。它将在发布后至少三年内收到安全更新。对以前的LTS Django 3.2的支持将于2024年4月结束。

与Python的兼容性

Django 4.2支持Python3.8、3.9、3.10、3.11和3.12(从4.2.8开始)。我们 highly recommend 并且仅官方支持每个系列的最新版本。

Django 4.2中的新特性

《心理3》支持

Django现在支持 psycopg 3.1.8版或更高版本。若要更新代码,请安装 psycopg library ,您不需要更改 ENGINE AS django.db.backends.postgresql 支持这两个库。

支持 psycopg2 很可能会在将来的某个时候被弃用和移除。

请注意, psycopg 3介绍了一些突破性的变化 psycopg2 。因此,您可能需要进行一些更改以说明 differences from psycopg2

关于列和表的注释

新的 Field.db_commentMeta.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

对入侵攻击的缓解

GZipMiddleware 现在包括对入侵攻击的缓解。它将向GZIP响应添加多达100个随机字节,以使入侵攻击变得更加困难。有关缓解技术的更多信息,请参阅 Heal The Breach (HTB) paper

内存中文件存储

新的 django.core.files.storage.InMemoryStorage 类提供了一种非持久性存储,可通过避免磁盘访问来加快测试速度。

自定义文件存储

新的 STORAGES 设置允许配置多个自定义文件存储后端。它还控制存储引擎以管理 files ( "default" 密钥)和 static files ( "staticfiles" 键)。

老的 DEFAULT_FILE_STORAGESTATICFILES_STORAGE 从本版本开始,不建议使用设置。

次要特征

django.contrib.admin

  • 管理员的浅色或深色主题现在可以在用户界面中切换,也可以设置为遵循系统设置。

  • 管理员的字体堆栈现在更喜欢系统用户界面字体,不再需要下载字体。此外,还可以使用css变量来更轻松地覆盖默认字体系列。

  • 这个 admin/delete_confirmation.html 模板现在有一些额外的块和脚本挂钩,以简化定制。

  • 已选择的选项 filter_horizontalfilter_vertical Widget现在是可过滤的。

  • 这个 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 serializer 现在输出 id 序列化功能的键,默认为对象的主键。

  • 这个 GDALRaster 类现在支持 pathlib.Path

  • 这个 GeoIP2 类现在支持 .mmdb 从DB-IP下载的文件。

  • OpenLayers模板微件不再包含内联CSS(这也会移除前者 map_css 阻止),以更好地遵守严格的内容安全策略。

  • OpenLayersWidget 现在基于OpenLayers 7.2.2(之前的4.6.5)。

  • 新的 isempty 查找和 IsEmpty() 表达式允许过滤PostGIS上的空几何图形。

  • 新的 FromWKB()FromWKT() 函数允许从熟知二进制(WKB)和熟知文本(WKT)表示创建几何图形。

django.contrib.postgres

django.contrib.sitemaps

django.contrib.staticfiles

  • ManifestStaticFilesStorage 现在提供了试验性的支持,用于替换 importexport 语句与其散列的对应物。如果您想尝试一下,可以使用子类 ManifestStaticFilesStorage 并将 support_js_module_import_aggregation 属性为 True

  • 新的 ManifestStaticFilesStorage.manifest_hash 属性提供清单中所有文件的哈希,并在其中一个文件发生更改时进行更改。

数据库后端

错误报告

表格

  • ModelForm 现在接受新的 Meta 选择权 formfield_callback 若要自定义表单域,请执行以下操作。

  • modelform_factory() 现在尊敬的是 formfield_callback 属性的属性 form 张氏 Meta

国际化

  • 增加了对中央库尔德语(索拉尼)的支持和翻译。

日志记录

  • 这个 django.db.backends 记录器现在记录事务管理查询 (BEGINCOMMIT ,以及 ROLLBACK )) DEBUG 水平。

管理命令

  • makemessages 命令现在支持具有私有子标记的区域设置,例如 nl_NL-x-informal

  • 新的 makemigrations --update 选项可将模型更改合并到最新的迁移中,并优化所产生的操作。

迁徙

  • 迁移现在支持序列化 enum.Flag 物体。

模型

  • QuerySet 现在广泛支持对以下内容进行筛选 窗口功能 除了在执行聚合时针对窗口函数的析取过滤器查找。

  • prefetch_related() 现在支持 Prefetch 具有切片查询集的对象。

  • Registering lookups 在……上面 Field 现在支持实例。

  • 新的 robust 论据 on_commit() 允许执行在成功提交数据库事务后可能失败的操作。

  • 新的 KT() 的键、索引或路径转换的文本值。 JSONField

  • Now 现在MySQL支持微秒精度,SQLite支持毫秒精度。

  • F() 输出以下内容的表达式 BooleanField 现在可以使用 ~F() (倒数运算符)。

  • Model 现在提供了一些使用数据库的方法的异步版本,使用 a 前缀: adelete()arefresh_from_db() ,以及 asave()

  • 相关管理器现在提供更改一组相关对象的方法的异步版本,使用 a 前缀: aadd()aclear()aremove() ,以及 aset()

  • CharField.max_length 不再需要在支持无限的PostgreSQL上设置 VARCHAR 柱子。

请求和响应

测试

  • 这个 test --debug-sql 选项现在使用以下选项设置SQL查询的格式 sqlparse

  • 这个 RequestFactoryAsyncRequestFactoryClient ,以及 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"})
    

公用事业

  • 新的 encoder 的参数 django.utils.html.json_script() 函数允许定制JSON编码器类。

  • 私人内部出售的副本 urllib.parse.urlsplit() 现在脱掉条带 '\r''\n' ,以及 '\t' (见 CVE-2022-0391bpo-43882 )。这是为了保护可能错误地使用内部 url_has_allowed_host_and_scheme() 函数,而不是使用文档中的某个函数来处理URL重定向。姜戈的功能没有受到影响。

  • 新的 django.utils.http.content_disposition_header() 函数返回一个 Content-Disposition 由指定的HTTP标头值 RFC 6266

验证器

  • 使用的常用密码列表 CommonPasswordValidator 更新到最新版本。

4.2中向后不兼容的更改

数据库后端API

本节介绍第三方数据库后端可能需要的更改。

  • DatabaseFeatures.allows_group_by_pk 被删除,因为它只是为了容纳MySQL扩展而保留,而MySQL 5.7.15中的正确函数依赖检测已经取代了该扩展。请注意 DatabaseFeatures.allows_group_by_selected_pks 仍然受支持,如果您的后端支持 GROUP BY 子句中指定的 SQL:1999 标准。

  • inspectdb 现在使用 display_size 从… DatabaseIntrospection.get_table_description() 而不是 internal_sizeCharField

已放弃对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支持MySQL8及更高版本。

不再支持PostgreSQL 11

对PostgreSQL 11的上游支持将于2023年11月结束。Django 4.2支持PostgreSQL 12及更高版本。

设置 update_fields 在……里面 Model.save() 现在可能需要

为了避免更新不必要的列, QuerySet.update_or_create() 现在过去了 update_fields 发送到 Model.save() 打电话。因此,在自定义中修改的任何字段 save() 方法应添加到 update_fields 调用前的关键字参数 super() 。看见 重写预定义的模型方法 了解更多详细信息。

已删除对MySQL上的原始聚合的支持

MySQL 8+允许函数依赖于 GROUP BY 列,因此删除了Django 4.2之前的按主表主键分组的解决方法。因此,使用 RawSQL() MySQL不再支持聚合,因为无法确定 GROUP BY 第。条。使用 聚合函数 取而代之的是。

杂类

  • 未登记的人 django.http.multipartparser.parse_header() 函数被删除。使用 django.utils.http.parse_header_parameters() 取而代之的是。

  • {% blocktranslate asvar %} 结果现在被标记为安全(用于(HTML)输出)。

  • 这个 autofocus 管理员搜索框中的Html属性被删除,因为它可能会让屏幕阅读器感到困惑。

  • 这个 makemigrations --check 选项不再创建丢失的迁移文件。

  • 这个 alias 论据 Expression.get_group_by_cols() 被移除。

  • 支持的最低版本 sqlparse 从0.2.2增加到0.3.1。

  • 未登记的人 negated 属性的参数 Exists 表达式将被删除。

  • 这个 is_summary 无证之辩 Query.add_annotation() 方法被移除。

  • 支持的最低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 现在验证一个 hostnamecertificates 。如果您需要以前限制较少且不推荐使用的行为,则可以使用子类 EmailBackend 并重写 ssl_context 财产。

4.2中弃用的功能

index_together option is deprecated in favor of indexes

这个 Meta.index_together 选项被弃用,而支持 indexes 选择。

迁移现有的 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的一部分,没有计划弃用或删除它,但不应该将其用于新的迁移。使用 AddIndexRemoveIndex 取而代之的是运营。

将编码的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() 方法已弃用。看见 recipes and best practices 因为使用了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.SHA1PasswordHasherdjango.contrib.auth.hashers.UnsaltedSHA1PasswordHasher ,以及 django.contrib.auth.hashers.UnsaltedMD5PasswordHasher 都已被弃用。

  • django.contrib.postgres.fields.CICharField 不推荐使用,而支持 CharField(db_collation="…") 不区分大小写的非确定性排序规则。

  • django.contrib.postgres.fields.CIEmailField 不推荐使用,而支持 EmailField(db_collation="…") 不区分大小写的非确定性排序规则。

  • django.contrib.postgres.fields.CITextField 不推荐使用,而支持 TextField(db_collation="…") 不区分大小写的非确定性排序规则。

  • django.contrib.postgres.fields.CIText 不推荐使用Mixin。

  • 这个 map_heightmap_width 的属性 BaseGeometryWidget 已弃用,请使用css来调整地图小部件的大小。

  • SimpleTestCase.assertFormsetError() 不推荐使用,而支持 assertFormSetError()

  • TransactionTestCase.assertQuerysetEqual() 不推荐使用,而支持 assertQuerySetEqual()

  • 将位置参数传递给 SignerTimestampSigner 建议使用仅关键字参数,而不推荐使用。

  • 这个 DEFAULT_FILE_STORAGE 设置已弃用,而是支持 STORAGES["default"]

  • 这个 STATICFILES_STORAGE 设置已弃用,而是支持 STORAGES["staticfiles"]

  • 这个 django.core.files.storage.get_storage_class() 函数已弃用。