Django 2.2 版本发行说明¶
2019 年 4 月 1 日
欢迎使用 Django 2.2 !
这些发布说明涵盖了 新功能,以及在从 Django 2.1 或更早版本升级时需要注意的一些 向后不兼容的更改。我们已经 开始了一些功能的弃用过程。
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Django 2.2 被指定为 长期支持版本。它将在发布后至少三年内接收安全更新。对于之前的 LTS 版本 Django 1.11,支持将在 2020 年 4 月结束。
Python 兼容性¶
Django 2.2 支持 Python 3.5、3.6、3.7、3.8(从 2.2.8 版开始),以及 3.9(从 2.2.17 版开始)。我们 强烈建议 并只官方支持每个系列的最新版本。
Django 2.2 的新功能有哪些呢?¶
约束¶
新的 CheckConstraint
和 UniqueConstraint
类允许添加自定义数据库约束。约束可以使用 Meta.constraints
选项添加到模型中。
次要特性¶
django.contrib.admin
¶
为
TabularInline
的列标题添加了一个 CSS 类。
django.contrib.auth
¶
如果接受,现在将
HttpRequest
作为RemoteUserBackend.configure_user()
的第一个位置参数传递。
django.contrib.gis
¶
django.contrib.postgres
¶
新的
BTreeIndex
、HashIndex
和SpGistIndex
类允许在数据库中创建B-Tree
、hash
和SP-GiST
索引。BrinIndex
现在具有autosummarize
参数。SearchQuery
的新参数search_type
允许搜索短语或原始表达式。
django.contrib.staticfiles
¶
在
collectstatic --ignore
选项中添加了路径匹配功能,以便可以使用像/vendor/*.js
这样的模式。
数据库后端¶
在 SQLite 上为
QuerySet.iterator()
添加了结果流式传输功能。
通用视图¶
新的
View.setup
钩子在调用dispatch()
之前初始化视图属性。它允许 mixins 设置实例属性,以便在子类中重用。
国际化¶
增加了对亚美尼亚语的支持和翻译。
管理命令¶
新的
--force-color
选项强制对命令输出进行着色。inspectdb
现在会为 PostgreSQL 上的外部表创建模型。inspectdb --include-views
现在会为 Oracle 和 PostgreSQL 上的物化视图创建模型。新的
inspectdb --include-partitions
选项允许在 PostgreSQL 上为分区表创建模型。在旧版本中,模型是在子表而不是父表中创建的。inspectdb
现在可以为 Oracle 和 PostgreSQL 自动检测DurationField
,以及为 SQLite 检测AutoField
。在 Oracle 上,如果可用,
dbshell
会使用rlwrap
包装。rlwrap
提供了命令历史记录和键盘输入的编辑功能。新的
makemigrations --no-header
选项可以避免在生成的迁移文件中写入头部注释。这个选项也适用于squashmigrations
。
迁移¶
新的
migrate --plan
选项会打印将执行的迁移操作列表。NoneType
现在可以在迁移中序列化。现在可以为迁移 注册自定义序列化程序。
模型¶
添加了对 PostgreSQL 运算符类 (
Index.opclasses
) 的支持。添加了对部分索引 (
Index.condition
) 的支持。将
QuerySet.bulk_create()
的新参数ignore_conflicts
设置为True
会告诉数据库忽略插入失败的行,即违反唯一性约束或其他检查的行。新的
ExtractIsoYear
函数从DateField
和DateTimeField
中提取 ISO-8601 周编号年,新的iso_year
查询允许按 ISO-8601 周编号年进行查询。新的
QuerySet.bulk_update()
方法允许高效地更新多个模型实例上的特定字段。Django 不再总是在执行单个查询时启动事务,例如
Model.save()
,QuerySet.update()
和Model.delete()
。这通过减少数据库往返次数来提高自动提交的性能。对于
Aggregate
类,增加了DISTINCT
聚合的处理。在Aggregate
子类上添加allow_distinct = True
作为类属性,允许在初始化时指定一个distinct
关键字参数,以确保聚合函数仅对expressions
的每个不同值调用一次。现在允许在具有中间模型的多对多关系上使用
RelatedManager.add()
、create()
、remove()
、set()
、get_or_create()
和update_or_create()
方法。新的through_defaults
参数用于指定新中间模型实例的值。
请求和响应¶
添加了
HttpRequest.headers
,以便简单访问请求的头部信息。
序列化¶
测试¶
新的
SimpleTestCase.assertURLEqual()
断言检查给定的 URL,忽略查询字符串的顺序。assertRedirects()
使用了这个新的断言。现在,测试
Client
在content_type='application/json'
时支持自动对列表和元组data
进行 JSON 序列化。新的
ORACLE_MANAGED_FILES
测试数据库设置允许使用 Oracle 管理文件 (OMF) 表空间。可延迟的数据库约束现在在 SQLite 3.20+ 上的每个
TestCase
测试结束时进行检查,就像其他支持可延迟约束的后端一样。对于较旧版本的 SQLite,这些检查没有实现,因为在那里需要昂贵的表内省。DiscoverRunner
现在会跳过未被 测试引用 的数据库的设置。
URLs¶
新的
ResolverMatch.route
属性存储匹配的 URL 模式的路由。
验证器¶
MaxValueValidator
、MinValueValidator
、MinLengthValidator
和MaxLengthValidator
现在接受可调用的limit_value
。
2.2 版本中的不向后兼容变更¶
数据库后端 API¶
本节介绍了第三方数据库后端可能需要的更改。
第三方数据库后端必须实现对表检查约束的支持,或将
DatabaseFeatures.supports_table_check_constraints
设置为False
。第三方数据库后端必须实现在插入时忽略约束或唯一性错误的支持,或将
DatabaseFeatures.supports_ignore_conflicts
设置为False
。第三方数据库后端必须实现对
DurationField
的内省,或将DatabaseFeatures.can_introspect_duration_field
设置为False
。DatabaseFeatures.uses_savepoints
现在默认为True
。第三方数据库后端必须实现对部分索引的支持,或将
DatabaseFeatures.supports_partial_indexes
设置为False
。移除了
DatabaseIntrospection.table_name_converter()
和column_name_converter()
。第三方数据库后端可能需要代替实现DatabaseIntrospection.identifier_converter()
。在这种情况下,DatabaseIntrospection.get_constraints()
返回的约束名称必须通过identifier_converter()
进行规范化。索引的 SQL 生成从
Index
移动到SchemaEditor
,并添加了以下SchemaEditor
方法:_create_primary_key_sql()
和_delete_primary_key_sql()
_delete_index_sql()
(与_create_index_sql()
配对使用)_delete_unique_sql
(与_create_unique_sql()
配对使用)_delete_fk_sql()
(与_create_fk_sql()
配对使用)_create_check_sql()
和_delete_check_sql()
移除了
DatabaseWrapper.__init__()
的第三个参数allow_thread_sharing
。
不再从基本的 ModelAdmin
类中收集管理操作¶
例如,在较旧版本的 Django 中:
from django.contrib import admin
class BaseAdmin(admin.ModelAdmin):
actions = ["a"]
class SubAdmin(BaseAdmin):
actions = ["b"]
SubAdmin
将具有操作 'a'
和 'b'
。
现在,actions
遵循标准的 Python 继承。要获得与以前相同的结果:
class SubAdmin(BaseAdmin):
actions = BaseAdmin.actions + ["b"]
django.contrib.gis
¶
支持 GDAL 1.9 和 1.10 的功能已被移除。
TransactionTestCase
序列化数据加载¶
现在,在 TransactionTestCase
的测试结束后,即在数据库刷新之后加载初始数据迁移。在旧版本中,这些数据在测试开始时加载,但这会阻止 test --keepdb
选项正常工作(整个测试套件结束后数据库为空)。除非您已自定义了 TransactionTestCase
的内部,否则这个变化不应影响您的测试。
sqlparse
是必需的依赖项¶
为了简化 Django 数据库处理的几个部分,现在 sqlparse 0.2.2+ 是一个必需的依赖项。它会随着 Django 自动安装。
cached_property
别名¶
在以下用法中:
from django.utils.functional import cached_property
class A:
@cached_property
def base(self):
return ...
alias = base
alias
不会被缓存。在可以检测到问题的情况下(Python 3.6 及更高版本),此类用法现在会引发 TypeError: Cannot assign the same cached_property to two different names ('base' and 'alias')
。
请改用以下方式:
import operator
class A:
...
alias = property(operator.attrgetter("base"))
代理模型的权限¶
代理模型的权限 现在使用代理模型的内容类型而不是具体模型的内容类型来创建。在运行 migrate
时,迁移将更新现有的权限。
在管理界面中,对于与其具体模型具有相同的 app_label
的代理模型,这个变化是透明的。然而,在旧版本中,对于具体模型具有不同 app_label
的代理模型的权限的用户不能访问管理中的模型。现在这个问题已经修复,但在升级之前,您可能希望审查这些代理模型的权限分配([add|view|change|delete]_myproxy
),以确保新的访问是合适的。
最后,代理模型的权限字符串必须更新以使用它们自己的 app_label
。例如,对于继承自 other_app.ConcreteModel
的 app.MyProxyModel
,请将 user.has_perm('other_app.add_myproxymodel')
更新为 user.has_perm('app.add_myproxymodel')
。
合并表单 Media
资源¶
现在,表单 Media
资源使用拓扑排序算法进行合并,因为旧的成对合并算法对某些情况不足够。不包含其依赖项的 CSS 和 JavaScript 文件现在可能会被错误地排序(而旧算法恰好由于巧合而产生了正确的结果)。
请审查所有的 Media
类以查找任何缺失的依赖项。例如,依赖于 django.jQuery
的小部件在 声明表单媒体资源 时必须指定 js=['admin/js/jquery.init.js', ...]
。
杂项¶
为了提高可读性,
UUIDField
表单字段现在会显示带有破折号的值,例如550e8400-e29b-41d4-a716-446655440000
,而不是550e8400e29b41d4a716446655440000
。在 SQLite 上,
PositiveIntegerField
和PositiveSmallIntegerField
现在包含一个检查约束,以防止在数据库中出现负值。如果您有现有的无效数据并运行重新创建表的迁移,您将看到CHECK constraint failed
。为了与 WSGI 服务器保持一致,测试客户端现在将
Content-Length
头设置为字符串而不是整数。django.utils.text.slugify()
的返回值不再标记为 HTML 安全。urlizetrunc
、truncatechars
、truncatechars_html
、truncatewords
和truncatewords_html
模板过滤器使用的默认截断字符现在是真正的省略号字符(…
)而不是 3 个点。您可能需要调整一些测试输出的比较。不再支持在模板文件系统加载器中使用字节串路径。
django.utils.http.urlsafe_base64_encode()
现在返回一个字符串而不是字节字符串,并且django.utils.http.urlsafe_base64_decode()
可能不再接受字节字符串作为参数。不再支持
cx_Oracle
版本低于 6.0。mysqlclient
的最低支持版本从 1.3.7 增加到 1.3.13。SQLite 的最低支持版本从 3.7.15 提高到 3.8.3 。
为了提供更语义化的查询数据,
NullBooleanSelect
现在呈现<option>
的值为unknown
、true
和false
,而不是1
、2
和3
。为了向后兼容,旧值仍然被接受为数据。Group.name
的max_length
从 80 增加到 150 个字符。现在在运行于 SQLite 3.20+ 上的测试中,违反可延迟数据库约束的行为将报错,就像其他支持此类约束的后端一样。
为了捕获使用错误,测试
Client
和django.utils.http.urlencode()
现在如果传递None
作为要编码的值会引发TypeError
,因为None
不能编码为 GET 和 POST 数据。要么传递空字符串,要么省略值。现在,
ping_google
管理命令默认使用https
而不是http
作为站点地图的 URL。如果你的站点使用 http,请使用新的ping_google --sitemap-uses-http
选项。如果你使用django.contrib.sitemaps.ping_google
函数,请将新的sitemap_uses_https
参数设置为False
。runserver
不再支持pyinotify
(已被 Watchman 替代)。当输入是
Decimal
时,Avg
、StdDev
和Variance
聚合函数现在返回Decimal
而不是float
。如果没有迁移的应用与具有迁移的应用有关系,那么在 SQLite 上的测试将失败。这自从 Django 1.7 添加迁移以来一直是一个已记录的限制,但现在它失败得更可靠。您将看到类似于
no such table: <app_label>_<model>
的错误导致测试失败。这在一些具有测试中没有迁移的模型的第三方应用中观察到。您必须为这些模型添加迁移。在
cache.delete()
或cache.get()
的key
参数中提供整数现在会引发ValueError
。由于已纳入 Transifex 的最新版本,某些语言的复数规则方程式已被更改。
备注
在 Django 2.2.12 中添加了处理同一语言的
.po
文件中包含不同复数方程的能力。
在 2.2 中被废弃的功能¶
模型的 Meta.ordering
将不再影响 GROUP BY
查询。¶
模型的 Meta.ordering
影响 GROUP BY
查询(例如 .annotate().values()
)是常见的引发混淆的原因。现在,这种查询会发出一个弃用警告,建议添加一个 order_by()
以保留当前查询。从 Django 3.1 开始,在这种查询中将忽略 Meta.ordering
。
杂项¶
django.utils.timezone.FixedOffset
已被弃用,建议使用datetime.timezone
。未记录的
QuerySetPaginator
别名django.core.paginator.Paginator
已被弃用。django.contrib.postgres
中的FloatRangeField
模型和表单字段已被弃用,推荐使用新名称DecimalRangeField
,以匹配数据库中使用的numrange
数据类型。FILE_CHARSET
设置已被弃用。从 Django 3.1 开始,从磁盘读取的文件必须是 UTF-8 编码的。django.contrib.staticfiles.storage.CachedStaticFilesStorage
已被弃用,因为它存在无法解决的问题。请改用ManifestStaticFilesStorage
或第三方云存储。现在,
RemoteUserBackend.configure_user()
方法的第一个位置参数是request
,如果该方法接受它的话。不支持不接受request
参数的覆盖方法,将在 Django 3.1 中移除。SimpleTestCase.allow_database_queries
、TransactionTestCase.multi_db
和TestCase.multi_db
属性已被弃用,推荐使用SimpleTestCase.databases
、TransactionTestCase.databases
和TestCase.databases
。这些新属性允许声明数据库依赖关系,以防止非默认数据库的意外查询在测试之间泄漏状态。以前的行为可以通过设置databases='__all__'
来实现,即allow_database_queries=True
和multi_db=True
。