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
事件。这允许视图在客户端在生成响应之前断开连接时执行任何必要的清理工作。有关更多详细信息,请参阅 处理断开连接。
装饰器
- 以下装饰器现在支持包装异步视图函数:
- cache_control()
- never_cache()
- no_append_slash()
- csrf_exempt()
- csrf_protect()
- ensure_csrf_cookie()
- requires_csrf_token()
- sensitive_variables()
- sensitive_post_parameters()
- gzip_page()
- condition()
conditional_page()
- etag()
- last_modified()
- require_http_methods()
- require_GET()
- require_POST()
- require_safe()
- vary_on_cookie()
- vary_on_headers()
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-describedby
HTML 属性,以使屏幕阅读器能够将表单字段与其帮助文本关联起来。 - 无效的表单字段现在包括
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 now allows showing the duration of the slowest tests using the test —durations option (available on 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
。