Django 5.0 版本发行说明

2023 年 12 月 4 日

欢迎使用 Django 5.0 !

这些发布说明涵盖了 新功能,以及一些在从 Django 4.2 或更早版本升级时需要注意的 不兼容变更。我们已经 开始了一些功能的弃用过程

如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。

Python 兼容性

Django 5.0 支持 Python 3.10、3.11 和 3.12。我们 强烈推荐 并且只官方支持每个系列的最新发布版本。

Django 4.2.x 系列是最后一个支持 Python 3.8 和 3.9 的版本。

对于较旧版本的 Django 的第三方库支持

在 Django 5.0 发布之后,我们建议第三方应用程序的作者停止对 4.2 之前的所有 Django 版本的支持。在那时,你应该能够使用 python -Wd 运行你包的测试,以便出现弃用警告。在进行弃用警告修复后,你的应用程序应该与 Django 5.0 兼容。

Django 5.0 新特性

管理界面中的分面过滤器

在管理界面的 changelist 中,当通过 UI 切换开启时,现在会显示已应用过滤器的分面计数。此行为可以通过新的 ModelAdmin.show_facets 属性进行更改。更多信息请参阅 Facets

简化的表单字段渲染模板

Django 5.0 引入了字段组(field group)的概念,以及字段组模板。这简化了渲染 Django 表单字段的相关元素,如标签、小部件、帮助文本和错误。

例如,下面的模板:

  1. <form>
  2. ...
  3. <div>
  4. {{ form.name.label_tag }}
  5. {% if form.name.help_text %}
  6. <div class="helptext" id="{{ form.name.auto_id }}_helptext">
  7. {{ form.name.help_text|safe }}
  8. </div>
  9. {% endif %}
  10. {{ form.name.errors }}
  11. {{ form.name }}
  12. <div class="row">
  13. <div class="col">
  14. {{ form.email.label_tag }}
  15. {% if form.email.help_text %}
  16. <div class="helptext" id="{{ form.email.auto_id }}_helptext">
  17. {{ form.email.help_text|safe }}
  18. </div>
  19. {% endif %}
  20. {{ form.email.errors }}
  21. {{ form.email }}
  22. </div>
  23. <div class="col">
  24. {{ form.password.label_tag }}
  25. {% if form.password.help_text %}
  26. <div class="helptext" id="{{ form.password.auto_id }}_helptext">
  27. {{ form.password.help_text|safe }}
  28. </div>
  29. {% endif %}
  30. {{ form.password.errors }}
  31. {{ form.password }}
  32. </div>
  33. </div>
  34. </div>
  35. ...
  36. </form>

现在可以简化为:

  1. <form>
  2. ...
  3. <div>
  4. {{ form.name.as_field_group }}
  5. <div class="row">
  6. <div class="col">{{ form.email.as_field_group }}</div>
  7. <div class="col">{{ form.password.as_field_group }}</div>
  8. </div>
  9. </div>
  10. ...
  11. </form>

as_field_group() 默认使用 "django/forms/field.html" 模板来渲染字段,并可以在每个项目、每个字段或每个请求的基础上进行自定义。请参阅 可重用的字段组模板

数据库计算的默认值

新的 Field.db_default 参数设置了一个数据库计算的默认值。例如:

  1. from django.db import models
  2. from django.db.models.functions import Now, Pi
  3. class MyModel(models.Model):
  4. age = models.IntegerField(db_default=18)
  5. created = models.DateTimeField(db_default=Now())
  6. circumference = models.FloatField(db_default=2 * Pi())

数据库生成的模型字段

新的 GeneratedField 允许创建数据库生成的列。此字段可用于所有支持的数据库后端,以创建一个始终从其他字段计算得到的字段。例如:

  1. from django.db import models
  2. from django.db.models import F
  3. class Square(models.Model):
  4. side = models.IntegerField()
  5. area = models.GeneratedField(
  6. expression=F("side") * F("side"),
  7. output_field=models.BigIntegerField(),
  8. db_persist=True,
  9. )

声明字段选择项的更多选项

Field.choices (用于模型字段)和 ChoiceField.choices (用于表单字段)在声明它们的值时提供了更多的灵活性。在以前的 Django 版本中,choices 应该是一个包含 2 元组的列表,或者是一个 枚举类型 的子类,但后者需要访问 .choices 属性以提供预期形式的值:

  1. from django.db import models
  2. Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
  3. SPORT_CHOICES = [
  4. ("Martial Arts", [("judo", "Judo"), ("karate", "Karate")]),
  5. ("Racket", [("badminton", "Badminton"), ("tennis", "Tennis")]),
  6. ("unknown", "Unknown"),
  7. ]
  8. class Winner(models.Model):
  9. name = models.CharField(...)
  10. medal = models.CharField(..., choices=Medal.choices)
  11. sport = models.CharField(..., choices=SPORT_CHOICES)

Django 5.0 添加了对接受映射或可调用对象的支持,而不是可迭代对象,并且不再需要直接使用 .choices 来扩展 枚举类型

  1. from django.db import models
  2. Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
  3. SPORT_CHOICES = { # Using a mapping instead of a list of 2-tuples.
  4. "Martial Arts": {"judo": "Judo", "karate": "Karate"},
  5. "Racket": {"badminton": "Badminton", "tennis": "Tennis"},
  6. "unknown": "Unknown",
  7. }
  8. def get_scores():
  9. return [(i, str(i)) for i in range(10)]
  10. class Winner(models.Model):
  11. name = models.CharField(...)
  12. medal = models.CharField(..., choices=Medal) # Using `.choices` not required.
  13. sport = models.CharField(..., choices=SPORT_CHOICES)
  14. score = models.IntegerField(choices=get_scores) # A callable is allowed.

在内部,每当更新 choices 值时,提供的 choices 将被规范化为包含 2 元组的列表,作为规范形式。有关更多信息,请查看 模型字段参考中的 choices

次要特性

django.contrib.admin

  • 新的 AdminSite.get_log_entries() 方法允许自定义站点列出的日志条目的查询集。
  • django.contrib.admin.AllValuesFieldListFilterChoicesFieldListFilterRelatedFieldListFilterRelatedOnlyFieldListFilter 管理筛选器现在处理多值查询参数。
  • XRegExp 升级到版本 5.1.1,从之前的版本 3.2.0。
  • 新的 AdminSite.get_model_admin() 方法返回给定模型类的管理类。
  • ModelAdmin.list_display 中的属性现在支持 boolean 属性。
  • jQuery 升级到版本 3.7.1,从之前的版本 3.6.4。

django.contrib.auth

django.contrib.contenttypes

django.contrib.gis

django.contrib.messages

django.contrib.postgres

异步视图

  • 在 ASGI 下,现在可以处理 http.disconnect 事件。这允许视图在客户端在生成响应之前断开连接时执行任何必要的清理工作。有关更多详细信息,请参阅 处理断开连接

装饰器

错误报告

文件存储

  • File.open() 现在将所有位置参数(*args)和关键字参数(**kwargs)传递给 Python 内置的 open()

表单

  • 新的 assume_scheme 参数用于 URLField,允许指定默认的 URL 方案。
  • 为了提高可访问性,进行了以下更改:
    • 现在表单字段包括 aria-describedby HTML 属性,以使屏幕阅读器能够将表单字段与其帮助文本关联起来。
    • 无效的表单字段现在包括 aria-invalid="true" HTML 属性。

国际化

  • 现在支持维吾尔语,并提供翻译。

迁移

模型

分页

信号

模板

  • 新的 escapeseq 模板过滤器将 escape 应用于序列的每个元素。

测试

验证器

5.0 版本中不向后兼容的变更

数据库后端 API

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

  • 如果数据库不支持将数据库函数用作默认值,则应将 DatabaseFeatures.supports_expression_defaults 设置为 False
  • 如果数据库不支持在 INSERT 查询中使用 DEFAULT 关键字,应将 DatabaseFeatures.supports_default_keyword_in_insert 设置为 False
  • 如果数据库不支持在批量 INSERT 查询中使用 DEFAULT 关键字,应将 DatabaseFeatures.supports_default_keyword_in_bulk_insert 设置为 False

django.contrib.gis

  • 移除对 GDAL 2.2 和 2.3 的支持。
  • 移除对 GEOS 3.6 和 3.7 的支持。

django.contrib.sitemaps

  • 移除了 django.contrib.sitemaps.ping_google() 函数和 ping_google 管理命令,因为 Google Sitemaps 的 ping 端点已被弃用,并将于 2024 年 1 月被移除。
  • 移除了 django.contrib.sitemaps.SitemapNotFound 异常类。

不再支持 MySQL 版本低于 8.0.11。

不再支持 MySQL 8.0.x 系列的预发布版本。Django 5.0 支持 MySQL 8.0.11 及更高版本。

在使用 QuerySet.update_or_create() 时,可能现在需要使用 create_defaults__exact

QuerySet.update_or_create() 现在支持参数 create_defaults。因此,任何在 update_or_create() 中使用具有名为 create_defaults 的字段的模型应该在查找中使用 create_defaults__exact 指定该字段。

迁移现有的在 MariaDB 10.7+ 上的 UUIDField

在 MariaDB 10.7+ 中,现在将 UUIDField 创建为 UUID 列,而不再是 CHAR(32) 列。因此,在 Django 版本小于 5.0 中创建的任何 UUIDField 都应该替换为由 CHAR(32) 支持的 UUIDField 子类:

  1. class Char32UUIDField(models.UUIDField):
  2. def db_type(self, connection):
  3. return "char(32)"
  4. def get_db_prep_value(self, value, connection, prepared=False):
  5. value = super().get_db_prep_value(value, connection, prepared)
  6. if value is not None:
  7. value = value.hex
  8. return value

例子:

  1. class MyModel(models.Model):
  2. uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)

应该变成:

  1. class Char32UUIDField(models.UUIDField): ...
  2. class MyModel(models.Model):
  3. uuid = Char32UUIDField(primary_key=True, default=uuid.uuid4)

运行 makemigrations 命令将生成一个包含无操作的 AlterField 操作的迁移。

杂项

  • 未记录的 BaseModelFormSet.save_existing() 方法的 instance 参数已重命名为 obj
  • 未记录的 django.contrib.admin.helpers.checkbox 已被移除。
  • 在 SQLite 上,整数字段现在会被验证为 64 位整数,以匹配 sqlite3 的行为。
  • 未记录的 Query.annotation_select_mask 属性已从字符串集更改为有序的字符串列表。
  • 如果未设置 width_fieldheight_field,则不再在 post_init 信号上调用 ImageField.update_dimension_fields()
  • 在 Oracle 上,Now 数据库函数现在使用 LOCALTIMESTAMP 而不是 CURRENT_TIMESTAMP
  • AdminSite.site_header 现在呈现在一个 <div> 标签中,而不是 <h1>。屏幕阅读器用户依赖标题元素在页面内导航。拥有两个 <h1> 元素会引起混淆,而且站点标题在所有页面上都重复出现,没有帮助。
  • 为了提高可访问性,管理员的主要内容区域和页眉内容区域现在呈现在 <main><header> 标签中,而不是 <div>
  • 在没有原生支持 SQL XOR 运算符的数据库上,作为异或(XOR)运算符的 ^ 现在会返回被奇数个操作数匹配的行,而不是严格匹配一个操作数。这与 MySQL、MariaDB 和 Python 的行为一致。
  • asgiref 的最低支持版本已从 3.6.0 增加到 3.7.0。
  • selenium 的最低支持版本已从 3.8.0 增加到 4.8.0。
  • AlreadyRegisteredNotRegistered 异常已从 django.contrib.admin.sites 移动到 django.contrib.admin.exceptions
  • SQLite 的最低支持版本已从 3.21.0 增加到 3.27.0。
  • 不再支持 cx_Oracle 版本小于 8.3。
  • 在应用程序注册表完全填充之前执行 SQL 查询现在会引发 RuntimeWarning
  • 对于非 UTF-8 编码的请求和 application/x-www-form-urlencoded 内容类型,将引发 BadRequest 异常。有关详细信息,请参阅 RFC 1866
  • colorama 的最低支持版本已增加到 0.4.6。
  • docutils 的最低支持版本已增加到 0.19。
  • 过滤查询集以防止整数溢出现在始终返回空查询集。因此,在这种情况下,你可能需要使用 ExpressionWrapper() 来对整数字段进行算术运算时进行 显式包装

在 5.0 版本中废弃的功能

杂项

  • DjangoDivFormRendererJinja2DivFormRenderer 过渡的表单渲染器已被弃用。
  • 将位置参数 nameviolation_error_message 传递给 BaseConstraint 已被弃用,建议使用关键字参数方式。
  • request 已添加到 ModelAdmin.lookup_allowed() 的签名中。不接受此参数的 ModelAdmin 子类的支持已被弃用。
  • ForeignObjectForeignObjectRelget_joining_columns() 方法已被弃用。从 Django 6.0 开始,django.db.models.sql.datastructures.Join 将不再回退到 get_joining_columns()。子类应该改为实现 get_joining_fields()
  • ForeignObject.get_reverse_joining_columns() 方法已被弃用。
  • 在 Django 6.0 中,forms.URLField 的默认方案将从 "http" 更改为 "https"。在 Django 5.x 发布周期中,将 FORMS_URLFIELD_ASSUME_HTTPS 过渡设置为 True 以选择假定 "https"
  • FORMS_URLFIELD_ASSUME_HTTPS 过渡设置已被弃用。
  • 不再支持在不传递 args 或 kwargs 的情况下调用 format_html()
  • cx_Oracle 的支持已被弃用,建议使用 oracledb 1.3.2+ Python 驱动程序。
  • DatabaseOperations.field_cast_sql() 已被弃用,建议使用 DatabaseOperations.lookup_cast()。从 Django 6.0 开始,BuiltinLookup.process_lhs() 将不再调用 field_cast_sql()。第三方数据库后端应该改为实现 lookup_cast()
  • django.db.models.enums.ChoicesMeta 元类已更名为 ChoicesType
  • Prefetch.get_current_queryset() 方法已被弃用。
  • 相关管理器和描述符的 get_prefetch_queryset() 方法已被弃用。从 Django 6.0 开始,get_prefetcher()prefetch_related_objects() 将不再回退到 get_prefetch_queryset()。子类应该改为实现 get_prefetch_querysets()

在 5.0 版本中移除的功能

这些功能已经完成了它们的弃用周期,并在 Django 5.0 中被移除。

有关这些更改的详细信息,包括如何删除对这些功能的使用,请参阅 在 4.0 版本中废弃的功能

  • SERIALIZE 测试设置已被移除。
  • 未记录的 django.utils.baseconv 模块已被移除。
  • 未记录的 django.utils.datetime_safe 模块已被移除。
  • USE_TZ 设置的默认值已从 False 更改为 True
  • 在不在请求上下文之外构建的站点地图的默认协议已从 'http' 更改为 'https'
  • DiscoverRunner.build_suite()DiscoverRunner.run_tests()extra_tests 参数已被移除。
  • 当没有行时,django.contrib.postgres.aggregates.ArrayAggJSONBAggStringAgg 聚合现在不再返回 [][]'',而是返回 None
  • USE_L10N 设置已被移除。
  • USE_DEPRECATED_PYTZ 过渡设置已被移除。
  • 对于 pytz 时区的支持已被移除。
  • is_dst 参数已从以下地方移除:
    • QuerySet.datetimes()
    • django.utils.timezone.make_aware()
    • 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.contrib.gis.admin.GeoModelAdminOSMGeoAdmin 类已被移除。
  • 未记录的 BaseForm._html_output() 方法已被移除。
  • 在渲染 ErrorDictErrorList 时返回 str 而不是 SafeString 的能力已被移除。

有关这些更改的详细信息,包括如何删除对这些功能的使用,请参阅 4.1 版本中弃用的功能

  • SitemapIndexItem.__str__() 方法已被移除。
  • CSRF_COOKIE_MASKED 过渡设置已被移除。
  • django.utils.functional.cached_property()name 参数已被移除。
  • django.contrib.postgres.constraints.ExclusionConstraintopclasses 参数已被移除。
  • 已移除将 errors=None 传递给 SimpleTestCase.assertFormError()assertFormsetError() 的未记录能力。
  • django.contrib.sessions.serializers.PickleSerializer 已被移除。
  • 不再允许在预取相关对象但没有提供 chunk_size 参数的查询集上使用 QuerySet.iterator()
  • 不再允许将未保存的模型实例传递给相关的过滤器。
  • RemoteUserBackend.configure_user() 子类的签名中需要包含 created=True
  • 已移除通过 GET 请求在 django.contrib.auth.views.LogoutViewdjango.contrib.auth.views.logout_then_login() 中进行登出的支持。
  • django.utils.timezone.utcdatetime.timezone.utc 的别名已被移除。
  • 不再允许将响应对象和表单/表单集名称传递给 SimpleTestCase.assertFormError()assertFormSetError()
  • django.contrib.gis.admin.OpenLayersWidget 已被移除。

  • django.contrib.auth.hashers.CryptPasswordHasher 已被移除。

  • "django/forms/default.html""django/forms/formsets/default.html" 模板已被移除。

  • 默认的表单和表单集呈现样式已更改为基于 div 的样式。
  • 不再允许向 Expression.asc()Expression.desc() 方法以及 OrderBy 表达式传递 nulls_first=Falsenulls_last=False