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 表单字段的相关元素,如标签、小部件、帮助文本和错误。
例如,下面的模板:
<form>
...
<div>
{{ form.name.label_tag }}
{% if form.name.help_text %}
<div class="helptext" id="{{ form.name.auto_id }}_helptext">
{{ form.name.help_text|safe }}
</div>
{% endif %}
{{ form.name.errors }}
{{ form.name }}
<div class="row">
<div class="col">
{{ form.email.label_tag }}
{% if form.email.help_text %}
<div class="helptext" id="{{ form.email.auto_id }}_helptext">
{{ form.email.help_text|safe }}
</div>
{% endif %}
{{ form.email.errors }}
{{ form.email }}
</div>
<div class="col">
{{ form.password.label_tag }}
{% if form.password.help_text %}
<div class="helptext" id="{{ form.password.auto_id }}_helptext">
{{ form.password.help_text|safe }}
</div>
{% endif %}
{{ form.password.errors }}
{{ form.password }}
</div>
</div>
</div>
...
</form>
现在可以简化为:
<form>
...
<div>
{{ form.name.as_field_group }}
<div class="row">
<div class="col">{{ form.email.as_field_group }}</div>
<div class="col">{{ form.password.as_field_group }}</div>
</div>
</div>
...
</form>
as_field_group() 默认使用 "django/forms/field.html" 模板来渲染字段,并可以在每个项目、每个字段或每个请求的基础上进行自定义。请参阅 可重用的字段组模板。
数据库计算的默认值¶
新的 Field.db_default 参数设置了一个数据库计算的默认值。例如:
from django.db import models
from django.db.models.functions import Now, Pi
class MyModel(models.Model):
age = models.IntegerField(db_default=18)
created = models.DateTimeField(db_default=Now())
circumference = models.FloatField(db_default=2 * Pi())
数据库生成的模型字段¶
新的 GeneratedField 允许创建数据库生成的列。此字段可用于所有支持的数据库后端,以创建一个始终从其他字段计算得到的字段。例如:
from django.db import models
from django.db.models import F
class Square(models.Model):
side = models.IntegerField()
area = models.GeneratedField(
expression=F("side") * F("side"),
output_field=models.BigIntegerField(),
db_persist=True,
)
声明字段选择项的更多选项¶
Field.choices (用于模型字段)和 ChoiceField.choices (用于表单字段)在声明它们的值时提供了更多的灵活性。在以前的 Django 版本中,choices 应该是一个包含 2 元组的列表,或者是一个 枚举类型 的子类,但后者需要访问 .choices 属性以提供预期形式的值:
from django.db import models
Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
SPORT_CHOICES = [
("Martial Arts", [("judo", "Judo"), ("karate", "Karate")]),
("Racket", [("badminton", "Badminton"), ("tennis", "Tennis")]),
("unknown", "Unknown"),
]
class Winner(models.Model):
name = models.CharField(...)
medal = models.CharField(..., choices=Medal.choices)
sport = models.CharField(..., choices=SPORT_CHOICES)
Django 5.0 添加了对接受映射或可调用对象的支持,而不是可迭代对象,并且不再需要直接使用 .choices 来扩展 枚举类型:
from django.db import models
Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")
SPORT_CHOICES = { # Using a mapping instead of a list of 2-tuples.
"Martial Arts": {"judo": "Judo", "karate": "Karate"},
"Racket": {"badminton": "Badminton", "tennis": "Tennis"},
"unknown": "Unknown",
}
def get_scores():
return [(i, str(i)) for i in range(10)]
class Winner(models.Model):
name = models.CharField(...)
medal = models.CharField(..., choices=Medal) # Using `.choices` not required.
sport = models.CharField(..., choices=SPORT_CHOICES)
score = models.IntegerField(choices=get_scores) # A callable is allowed.
在内部,每当更新 choices 值时,提供的 choices 将被规范化为包含 2 元组的列表,作为规范形式。有关更多信息,请查看 模型字段参考中的 choices。
次要特性¶
django.contrib.admin¶
新的
AdminSite.get_log_entries()方法允许自定义站点列出的日志条目的查询集。django.contrib.admin.AllValuesFieldListFilter、ChoicesFieldListFilter、RelatedFieldListFilter和RelatedOnlyFieldListFilter管理筛选器现在处理多值查询参数。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¶
PBKDF2 密码哈希器的默认迭代次数从 600,000 增加到 720,000。
现在提供了新的异步函数,使用
a前缀:django.contrib.auth.aauthenticate()、aget_user()、alogin()、alogout()和aupdate_session_auth_hash()。AuthenticationMiddleware现在添加了一个HttpRequest.auser()异步方法,用于返回当前已登录的用户。新的
django.contrib.auth.hashers.acheck_password()异步函数和AbstractBaseUser.acheck_password()方法允许异步检查用户密码。
django.contrib.contenttypes¶
QuerySet.prefetch_related()现在支持在结果集中存在非同质的情况下预取GenericForeignKey。
django.contrib.gis¶
新的
ClosestPoint()函数返回几何图形上距离另一个几何图形最近的二维点。GIS 聚合函数 现在支持
filter参数。添加了对 GDAL 3.7 和 GEOS 3.12 的支持。
新的
GEOSGeometry.equals_identical()方法允许逐点等价检查几何图形。
django.contrib.messages¶
新的
MessagesTestMixin.assertMessages()断言方法允许测试添加到response的messages。
django.contrib.postgres¶
ExclusionConstraint的新属性violation_error_code允许在 模型验证 期间自定义ValidationError引发的code。
异步视图¶
在 ASGI 下,现在可以处理
http.disconnect事件。这允许视图在客户端在生成响应之前断开连接时执行任何必要的清理工作。有关更多详细信息,请参阅 处理断开连接。
装饰器¶
以下装饰器现在支持包装异步视图函数:
conditional_page()xframe_options_deny()xframe_options_sameorigin()xframe_options_exempt()
错误报告¶
sensitive_variables()和sensitive_post_parameters()现在可以与异步函数一起使用。
文件存储¶
File.open()现在将所有位置参数(*args)和关键字参数(**kwargs)传递给 Python 内置的open()。
表单¶
新的
assume_scheme参数用于URLField,允许指定默认的 URL 方案。为了提高可访问性,进行了以下更改:
现在表单字段包括
aria-describedbyHTML 属性,以使屏幕阅读器能够将表单字段与其帮助文本关联起来。无效的表单字段现在包括
aria-invalid="true"HTML 属性。
国际化¶
现在支持维吾尔语,并提供翻译。
迁移¶
现在支持对使用
functools.cache()或functools.lru_cache()装饰的函数进行序列化,无需编写自定义序列化器。
模型¶
QuerySet.update_or_create()和QuerySet.aupdate_or_create()方法的新create_defaults参数允许为创建操作指定不同的字段值。BaseConstraint、CheckConstraint和UniqueConstraint的新violation_error_code属性允许自定义在 模型验证 过程中引发的ValidationError的code。Model.save()的 force_insert 参数现在允许指定必须强制插入的父类的元组。当启用
update_conflicts参数时,QuerySet.bulk_create()和QuerySet.abulk_create()方法现在会为每个模型实例设置主键(如果数据库支持的话)。新的
UniqueConstraint.nulls_distinct属性允许自定义在 PostgreSQL 15+ 上对NULL值的处理方式。新的
aget_object_or_404()和aget_list_or_404()异步快捷方式允许异步获取对象。新的
aprefetch_related_objects()函数允许异步预取模型实例。QuerySet.aiterator()现在支持之前对prefetch_related()的调用。在 MariaDB 10.7+ 上,
UUIDField现在将创建为UUID列,而不是CHAR(32)列。有关 迁移现有的在 MariaDB 10.7+ 上的 UUIDField 的更多详细信息,请参阅迁移指南。Django 现在支持 oracledb 版本 1.3.2 或更高版本。从此版本开始,对
cx_Oracle的支持已被弃用,并将在 Django 6.0 中移除。
分页¶
新的
django.core.paginator.Paginator.error_messages参数允许自定义由Paginator.page()引发的错误消息。
信号¶
新的
Signal.asend()和Signal.asend_robust()方法允许异步信号分发。信号接收器可以是同步或异步的,将自动适应正确的调用方式。
模板¶
测试¶
Client和AsyncClient现在提供异步方法,使用a前缀:asession()、alogin()、aforce_login()和alogout()。AsyncClient现在支持follow参数。DiscoverRunner现在允许使用test --durations选项(适用于 Python 3.12+)显示最慢测试的持续时间。
验证器¶
StepValueValidator的新offset参数允许为有效值指定偏移量。
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 子类:
class Char32UUIDField(models.UUIDField):
def db_type(self, connection):
return "char(32)"
def get_db_prep_value(self, value, connection, prepared=False):
value = super().get_db_prep_value(value, connection, prepared)
if value is not None:
value = value.hex
return value
例子:
class MyModel(models.Model):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
应该变成:
class Char32UUIDField(models.UUIDField): ...
class MyModel(models.Model):
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_field和height_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。AlreadyRegistered和NotRegistered异常已从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 版本中废弃的功能¶
杂项¶
DjangoDivFormRenderer和Jinja2DivFormRenderer过渡的表单渲染器已被弃用。将位置参数
name和violation_error_message传递给BaseConstraint已被弃用,建议使用关键字参数方式。request已添加到ModelAdmin.lookup_allowed()的签名中。不接受此参数的ModelAdmin子类的支持已被弃用。ForeignObject和ForeignObjectRel的get_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.ArrayAgg、JSONBAgg和StringAgg聚合现在不再返回[]、[]和'',而是返回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.GeoModelAdmin和OSMGeoAdmin类已被移除。未记录的
BaseForm._html_output()方法已被移除。在渲染
ErrorDict和ErrorList时返回str而不是SafeString的能力已被移除。
有关这些更改的详细信息,包括如何删除对这些功能的使用,请参阅 4.1 版本中弃用的功能。
SitemapIndexItem.__str__()方法已被移除。CSRF_COOKIE_MASKED过渡设置已被移除。django.utils.functional.cached_property()的name参数已被移除。django.contrib.postgres.constraints.ExclusionConstraint的opclasses参数已被移除。已移除将
errors=None传递给SimpleTestCase.assertFormError()和assertFormsetError()的未记录能力。django.contrib.sessions.serializers.PickleSerializer已被移除。不再允许在预取相关对象但没有提供
chunk_size参数的查询集上使用QuerySet.iterator()。不再允许将未保存的模型实例传递给相关的过滤器。
在
RemoteUserBackend.configure_user()子类的签名中需要包含created=True。已移除通过
GET请求在django.contrib.auth.views.LogoutView和django.contrib.auth.views.logout_then_login()中进行登出的支持。django.utils.timezone.utc到datetime.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=False或nulls_last=False。