Django 1.10 版本发行说明

2016 年 8 月 1 日

欢迎来到 Django 1.10 版本!

这些发布说明涵盖了 新功能,以及一些 不兼容的更改,在从 Django 1.9 或更早版本升级时,您需要注意这些更改。我们已经 放弃了一些功能,它们已经达到了停用周期的末尾,同时我们已经 开始了一些功能的停用过程

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

Python 兼容性

与 Django 1.9 一样,Django 1.10 需要 Python 2.7、3.4 或 3.5。我们 强烈建议 并且只正式支持每个系列的最新版本。

Django 1.10 新特性

PostgreSQL 的全文搜索

django.contrib.postgres 现在包括一个 数据库函数集合,允许使用全文搜索引擎。您可以在关系数据库中跨多个字段进行搜索,将搜索与其他查找组合使用,使用不同的语言配置和权重,以及按相关性对结果进行排名。

它还现在包括 trigram 支持,使用 trigram_similar 查找以及 TrigramSimilarityTrigramDistance 表达式。

新式中间件

引入了一种新的中间件风格,以解决旧式中间件的请求/响应层次不严格的问题,这在 DEP 0005 中有描述。您需要 调整旧的自定义中间件,并从 MIDDLEWARE_CLASSES 设置切换到新的 MIDDLEWARE 设置以充分利用这些改进。

官方支持 Unicode 用户名

django.contrib.auth 中的 User 模型最初只接受用户名中的 ASCII 字母和数字。尽管这不是一个故意的选择,在使用 Python 3 时,Unicode 字符一直都被接受。

用户名验证器现在默认情况下仅在 Python 3 上明确接受 Unicode 字符。

自定义用户模型可以使用新的 ASCIIUsernameValidatorUnicodeUsernameValidator

次要特性

django.contrib.admin

  • 对于运行在子路径上的站点,每个管理页面顶部的默认 “查看站点”链接的 URL 现在将指向 request.META['SCRIPT_NAME'] (如果设置了),而不是 /
  • 现在,在添加或编辑对象后出现的成功消息中包含到对象的更改表单的链接。
  • 所有内联 JavaScript 都已移除,因此您可以启用 Content-Security-Policy HTTP 标头(如果需要的话)。
  • 新的 InlineModelAdmin.classes 属性允许在内联字段集上指定类。具有 collapse 类的内联将初始折叠,并且它们的标题将有一个小的 “显示” 链接。
  • 如果用户没有添加权限,模型的更改列表上的 object-tools 区块现在将被呈现(没有添加按钮)。这在这种情况下更容易添加自定义工具。
  • LogEntry 模型现在将更改消息存储在 JSON 结构中,以便可以使用当前活动的语言动态翻译消息。现在,首选的检索更改消息的方式是使用新的 LogEntry.get_change_message() 方法。
  • ModelAdmin.raw_id_fields 中选定的字段的对象现在具有指向对象的更改表单的链接。
  • 如果字段可为空,为 DateFieldListFilter 添加了 “无日期” 和 “有日期” 选项。
  • 管理后台中嵌入的 jQuery 库已经从 2.1.4 版本升级到 2.2.3 版本。

django.contrib.auth

  • 增加了对 Argon2 密码哈希 的支持。它被推荐用于替代 PBKDF2,但不是默认选项,因为它需要一个第三方库。
  • PBKDF2 密码哈希的默认迭代次数已增加 25%。这个向后兼容的更改不会影响那些已经子类化了 django.contrib.auth.hashers.PBKDF2PasswordHasher 以更改默认值的用户。
  • django.contrib.auth.views.logout() 视图发送 “no-cache” 标头,以防止 Safari 缓存重定向并阻止用户注销的问题。
  • 新增了可选的 backend 参数以供 django.contrib.auth.login() 使用,允许在没有凭据的情况下使用它。
  • 新的 LOGOUT_REDIRECT_URL 设置控制了 django.contrib.auth.views.logout() 视图的重定向,如果视图没有得到一个 next_page 参数。
  • 新的 redirect_authenticated_user 参数用于 django.contrib.auth.views.login() 视图,允许重定向已经经过身份验证的用户访问登录页面。
  • 新的 AllowAllUsersModelBackendAllowAllUsersRemoteUserBackend 忽略了 User.is_active 的值,而 ModelBackendRemoteUserBackend 现在拒绝不活动的用户。

django.contrib.gis

django.contrib.postgres

  • 为了方便起见,HStoreField 现在将其键和值转换为字符串。

django.contrib.sessions

  • clearsessions 管理命令现在会删除基于文件的会话。

django.contrib.sites

django.contrib.staticfiles

  • static 模板标签现在如果在 INSTALLED_APPS 中,将使用 django.contrib.staticfiles。这对于第三方应用程序特别有用,现在它们可以始终使用 {% load static %}``(而不是 ``{% load staticfiles %}{% load static from staticfiles %}),并且不必担心是否安装了 staticfiles 应用程序。
  • 您可以通过自定义 AppConfig 更容易地 自定义 collectstatic --ignore 选项。

缓存

  • 基于文件的缓存后端现在使用最高的 pickling 协议。

CSRF

  • 默认的 CSRF_FAILURE_VIEWviews.csrf.csrf_failure() 现在接受一个可选的 template_name 参数,默认为 '403_csrf.html',用于控制渲染页面的模板。
  • 为了防止 BREACH 攻击,CSRF 保护机制现在会在每个请求中更改表单令牌的值(同时保持不变的秘密,可用于验证不同的令牌)。

数据库后端

  • 临时数据减法在所有后端上得到了统一。
  • 如果数据库支持,后端可以设置 DatabaseFeatures.can_return_ids_from_bulk_insert=True 并实现 DatabaseOperations.fetch_returned_insert_ids(),以便在使用 QuerySet.bulk_create() 创建的对象上设置主键。
  • 为各种表达式(FuncWhenCaseOrderBy)的 as_sql() 方法添加了关键字参数,允许数据库后端在不更改 self 的情况下自定义它们,这在使用不同的数据库后端时不安全。参见 Func.as_sql()arg_joiner**extra_context 参数的示例。

文件存储

表单

  • 如果安装了 django.contrib.staticfiles,则现在会使用它来提供表单和小部件的 Media
  • CharField 渲染的 <input> 标签现在如果字段具有 min_length,则会包含一个 minlength 属性。
  • 现在,必填表单字段具有 required HTML 属性。将新的 Form.use_required_attribute 属性设置为 False 可以禁用它。在表单集的表单上不包括 required 属性,因为在添加和删除表单集时,浏览器验证可能不正确。

通用视图

  • View 类现在可以从 django.views 中导入。

国际化

  • i18n_patterns() 辅助函数现在可以在使用 request.urlconf 指定的根 URL 配置中使用。
  • 通过将 i18n_patterns() 的新参数 prefix_default_language 设置为 False,您可以允许在没有 URL 前缀的情况下访问默认语言。
  • 现在,当在 POSTGET 中没有 next 参数时,set_language() 对于 AJAX 请求会返回 204 状态码(No Content)。
  • JavaScriptCatalogJSONCatalog 类视图取代了不推荐使用的 javascript_catalog()json_catalog() 函数视图。新视图与旧视图几乎相同,唯一的区别是,默认情况下,新视图会从所有已安装的应用程序中收集 djangojs 翻译域中的所有 JavaScript 字符串,而不仅仅是来自 LOCALE_PATHS 的 JavaScript 字符串。

管理命令

  • 现在,call_command() 会返回从 command.handle() 方法返回的值。
  • 新的 check —fail-level 选项允许指定消息级别,该级别将导致命令以非零状态退出。
  • 新的 makemigrations —check 选项在检测到模型更改而没有迁移时,使命令以非零状态退出。
  • makemigrations 现在会显示生成的迁移文件的路径。
  • shell —interface 选项现在接受 python,以强制使用 “plain” Python 解释器。
  • 新的 shell —command 选项允许您以 Django 用户身份运行命令并退出,而不是打开交互式 shell。
  • 如果指定了代理模型(导致没有输出)而没有指定其具体的父模型,dumpdata 现在会显示警告。
  • 新的 BaseCommand.requires_migrations_checks 属性可以设置为 True,如果您希望您的命令在磁盘上的迁移集与数据库中的迁移不匹配时打印警告,就像 runserver 一样。
  • 为了辅助测试,call_command() 现在接受一个命令对象作为第一个参数。
  • shell 命令在使用 libedit 的系统上支持制表符自动完成,例如 macOS。
  • inspectdb 命令允许您通过将表的名称指定为参数来选择应该进行检查的表。

迁移

  • 新增支持序列化 enum.Enum 对象。
  • RunSQLRunPython 操作中添加了 elidable 参数,以允许在压缩迁移时删除它们。
  • 通过在 Migration 上设置 atomic 属性,添加了对 非原子迁移 的支持。
  • migratemakemigrations 命令现在会 检查一致的迁移历史。如果它们发现某些已应用的迁移存在未应用的依赖项,将会引发 InconsistentMigrationHistory 异常。
  • pre_migrate()post_migrate() 信号现在会分发它们的迁移 planapps

模型

  • 来自代理模型的反向外键现在会传播到它们的具体类。指向代理模型的 ForeignKey 所附加的反向关系现在可以作为描述符在代理模型类上访问,并且可以在查询集过滤中引用。
  • 新的 Field.rel_db_type() 方法返回了诸如 ForeignKeyOneToOneField 这样指向另一个字段的字段的数据库列数据类型。
  • Func 添加了 arity 类属性。此属性可用于设置函数接受的参数数量。
  • 新增了 BigAutoField,它的行为类似于 AutoField,但它保证适合于范围从 19223372036854775807 的数字。
  • 可以不带任何参数调用 QuerySet.in_bulk(),以返回查询集中的所有对象。
  • related_query_name 现在支持使用 '%(app_label)s''%(class)s' 字符串进行应用标签和类的插值。
  • 允许覆盖从抽象基类继承的模型字段。
  • prefetch_related_objects() 函数现在是一个公共 API。
  • QuerySet.bulk_create() 在使用 PostgreSQL 时会设置对象的主键。
  • 新增了 Cast 数据库函数。
  • 现在,代理模型可以继承多个共享非抽象父类的代理模型。
  • 新增了 Extract 函数,用于提取日期时间组件作为整数,例如年份和小时。
  • 新增了 Trunc 函数,用于将日期或日期时间截断到一个重要的组件。它们使得可以执行类似每天销售或每小时销售的查询。
  • Model.__init__() 现在会从关键字参数中设置虚拟字段的值。
  • 新的 Meta.base_manager_nameMeta.default_manager_name 选项允许分别控制 _base_manager_default_manager

请求和响应

  • 在调试视图中添加了 request.user
  • 添加了 HttpResponse 的方法 readable()seekable(),以使实例成为类似流的对象,并允许将其包装在 io.TextIOWrapper 中。
  • 添加了 HttpRequest.content_typecontent_params 属性,这些属性从 CONTENT_TYPE 标头中解析而来。
  • request.COOKIES 的解析器被简化,以更好地匹配浏览器的行为。request.COOKIES 现在可以包含根据 RFC 6265 无效但可以通过 document.cookie 设置的 cookie。

序列化

  • django.core.serializers.json.DjangoJSONEncoder 现在知道如何序列化懒惰字符串,通常用于可翻译的内容。

模板

  • DjangoTemplates 后端和 Engine 类中添加了 autoescape 选项。
  • if 标签中添加了 isis not 比较运算符。
  • 允许使用 dictsort 根据指定索引处的元素对列表中的列表进行排序。
  • debug() 上下文处理器包含了所有数据库别名的查询,而不仅仅是默认别名。
  • extendsinclude 模板标签的字符串参数添加了相对路径支持。

测试

URLs

  • django.setup() 中的一个新添加允许在请求/响应周期之外发生的 URL 解析(例如在管理命令和独立脚本中)在设置 FORCE_SCRIPT_NAME 时考虑到它。

验证器

  • URLValidator 现在将域名标签的长度限制为 63 个字符,域名的总长度限制为 253 个字符,符合 RFC 1034 的规定。
  • int_list_validator() 现在接受一个可选的布尔参数 allow_negative,默认为 False,以允许负整数。

1.10 中的不向后兼容的变更

警告

除了本节中概述的更改之外,请务必查看 在 1.10 中移除的功能,了解已经到达了弃用周期终点并因此被移除的功能。如果您没有在给定功能的弃用时间表内更新您的代码,它的移除可能会被视为不兼容的更改。

数据库后端 API

  • GIS 的 AreaField 使用一个未指定的底层数字类型,实际上可以是任何 Python 数值类型。从数据库中检索到的 decimal.Decimal 值现在被转换为 float,以便更容易将它们与 GIS 库使用的值结合在一起。
  • 为了启用时间减法,您必须将数据库功能标志 supports_temporal_subtraction 设置为 True,并实现 DatabaseOperations.subtract_temporals() 方法。该方法应返回计算``lhs`` 和 rhs 参数之间差异的微秒数所需的 SQL 和参数,其数据类型用于存储 DurationField

Django 1.8 添加了 select_related() 中非关系字段的验证:

  1. >>> Book.objects.select_related("title")
  2. Traceback (most recent call last):
  3. ...
  4. FieldError: Non-relational field given in select_related: 'title'

但是现在它禁止了嵌套的非关系字段,而之前没有禁止。

  1. >>> Book.objects.select_related("author__name")
  2. Traceback (most recent call last):
  3. ...
  4. FieldError: Non-relational field given in select_related: 'name'

_meta.get_fields() 为代理模型返回一致的反向字段。

在 Django 1.10 之前,当在代理模型上调用 get_fields() 方法时,返回的反向字段与其代理的具体类相比是不同的。这种不一致性已经通过在两种情况下都返回指向具体类或其代理之一的字段的完整集合来修复。

AbstractUser.usernamemax_length 增加到了 150。

包括了一个针对 django.contrib.auth.models.User.username 的迁移。如果您有一个继承自 AbstractUser 的自定义用户模型,您需要为您的用户模型生成并应用一个数据库迁移。

我们考虑将用户名的最大长度增加到 254 个字符,以更容易允许使用电子邮件地址(限制为 254 个字符)作为用户名,但由于 MySQL 的限制而拒绝了这个提案。当使用 utf8mb4 编码(推荐用于正确支持 Unicode)时,默认情况下,MySQL 只能创建包含 191 个字符的唯一索引。因此,如果您需要更长的长度,请使用自定义用户模型。

如果您想保留用户名的 30 个字符限制,请在创建用户或更改用户名时使用自定义表单:

  1. from django.contrib.auth.forms import UserCreationForm
  2. class MyUserCreationForm(UserCreationForm):
  3. username = forms.CharField(
  4. max_length=30,
  5. help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
  6. )

如果您希望在管理员中保留这个限制,可以将 UserAdmin.add_form 设置为使用以下表单:

  1. from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
  2. from django.contrib.auth.models import User
  3. class UserAdmin(BaseUserAdmin):
  4. add_form = MyUserCreationForm
  5. admin.site.unregister(User)
  6. admin.site.register(User, UserAdmin)

停止支持 PostgreSQL 9.1

PostgreSQL 9.1 的上游支持将在 2016 年 9 月结束。因此,Django 1.10 将 PostgreSQL 9.2 设置为其正式支持的最低版本。

runserver 输出经过日志记录

runserver 命令的请求和响应处理发送到 django.server 日志记录器,而不是发送到 sys.stderr。如果您禁用了 Django 的日志配置或使用自己的配置覆盖了它,如果您想看到该输出,您需要添加适当的日志配置:

  1. LOGGING = {
  2. # ...
  3. "formatters": {
  4. "django.server": {
  5. "()": "django.utils.log.ServerFormatter",
  6. "format": "[%(server_time)s] %(message)s",
  7. }
  8. },
  9. "handlers": {
  10. "django.server": {
  11. "level": "INFO",
  12. "class": "logging.StreamHandler",
  13. "formatter": "django.server",
  14. },
  15. },
  16. "loggers": {
  17. "django.server": {
  18. "handlers": ["django.server"],
  19. "level": "INFO",
  20. "propagate": False,
  21. }
  22. },
  23. }

auth.CustomUserauth.ExtensionUser 测试模型已被移除。

自 Django 1.8 开始为 contrib 应用程序引入迁移以来,这些自定义用户测试模型的表不再创建,使它们无法在测试环境中使用。

在 Django 之外反序列化模型时,应用程序注册表不再自动填充。

在反序列化模型时,不再自动填充应用程序注册表。这在 Django 1.7.2 中添加,是为了允许在 Django 之外反序列化模型,比如在 RQ worker 中,而不需要调用 django.setup(),但这会导致死锁的可能性。在 RQ 的情况下,为了适应您的代码,您可以 提供自己的工作脚本,其中调用 django.setup()

删除了非空外键字段的空值赋值检查。

在旧版本中,将 None 分配给非空 ForeignKeyOneToOneField 会引发 ValueError('Cannot assign None: "model.field" does not allow null values.')。为了与没有类似检查的其他模型字段保持一致,此检查已被移除。

从默认的 PASSWORD_HASHERS 设置中移除了弱密码哈希器。

Django 0.90 将密码存储为未加盐的 MD5 。 Django 0.91 添加了对加盐 SHA1 的支持,并在用户登录时自动升级密码。 Django 1.4 将 PBKDF2 作为默认密码哈希器。

如果您有一个旧的 Django 项目,其中包含使用 MD5 或 SHA1(即使使用了盐值)编码的密码,请注意,这些密码可以在今天的硬件上相对容易地被破解。为了让 Django 用户确认继续使用弱哈希器,以下哈希器已从默认的 PASSWORD_HASHERS 设置中移除:

  1. "django.contrib.auth.hashers.SHA1PasswordHasher"
  2. "django.contrib.auth.hashers.MD5PasswordHasher"
  3. "django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"
  4. "django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"
  5. "django.contrib.auth.hashers.CryptPasswordHasher"

考虑使用一个 包装的密码哈希器 来加强数据库中的哈希值。如果这不可行,可以将 PASSWORD_HASHERS 设置添加到您的项目中,并添加回您需要的任何哈希器。

您可以像这样检查您的数据库是否具有任何已删除的哈希器:

  1. from django.contrib.auth import get_user_model
  2. User = get_user_model()
  3. # Unsalted MD5/SHA1:
  4. User.objects.filter(password__startswith="md5$$")
  5. User.objects.filter(password__startswith="sha1$$")
  6. # Salted MD5/SHA1:
  7. User.objects.filter(password__startswith="md5$").exclude(password__startswith="md5$$")
  8. User.objects.filter(password__startswith="sha1$").exclude(password__startswith="sha1$$")
  9. # Crypt hasher:
  10. User.objects.filter(password__startswith="crypt$$")
  11. from django.db.models import CharField
  12. from django.db.models.functions import Length
  13. CharField.register_lookup(Length)
  14. # Unsalted MD5 passwords might not have an 'md5$$' prefix:
  15. User.objects.filter(password__length=32)

Field.get_prep_lookup()Field.get_db_prep_lookup() 方法已被移除。

如果您有一个自定义字段实现了这两种方法中的任何一种,请为其注册一个自定义查找。例如:

  1. from django.db.models import Field
  2. from django.db.models.lookups import Exact
  3. class MyField(Field):
  4. ...
  5. class MyFieldExact(Exact):
  6. def get_prep_lookup(self):
  7. # do_custom_stuff_for_myfield
  8. ...
  9. MyField.register_lookup(MyFieldExact)

django.contrib.gis

  • 不再支持 SpatiaLite < 3.0 和 GEOS < 3.3 。
  • add_postgis_srs() 的向后兼容别名已被移除,应使用 django.contrib.gis.utils.add_srs_entry()
  • 在 Oracle/GIS 上,Area 聚合函数现在返回一个 float,而不再是 decimal.Decimal。(它仍然以平方米为单位包装。)
  • 默认情况下,GEOSGeometry 的表示形式(WKT 输出)现在默认被修剪。也就是说,不再是 POINT (23.0000000000000000 5.5000000000000000),而是 POINT (23 5.5)

请求体的最大大小以及 GET/POST 参数的数量受到限制。

两个新配置有助于减轻通过大型请求发起的拒绝服务攻击:

接收异常大表单提交的应用程序可能需要调整这些设置。

杂项

  • QuerySetrepr() 现在在调试时会包装在 <QuerySet > 中,以便与普通列表进行区分。
  • utils.version.get_version() 返回符合 PEP 440 的候选版本(例如 ‘1.10rc1’ 而不是 ‘1.10c1’)。
  • 现在要求 CSRF 令牌值必须是 64 个字母数字字符串;默认情况下,由旧版 Django 设置的 32 个字母数字值将自动替换为 64 个字符的字符串。其他值将被视为无效。这应该只会影响替换这些令牌的开发人员或用户。
  • LOGOUT_URL 设置已删除,因为自 1.0 版本以来 Django 不再使用它。如果你在项目中使用了它,可以将其添加到项目的设置中。默认值是 '/accounts/logout/'
  • 具有 close() 方法的对象,例如文件和生成器,传递给 HttpResponse 现在会立即关闭,而不是在 WSGI 服务器调用响应的 close() 方法时关闭。
  • QuerySet.update_or_create() 中删除了多余的 transaction.atomic() 调用。这可能会影响 TransactionTestCase.assertNumQueries() 测试的查询计数。
  • BaseCommand.execute(**options) 中删除了对 skip_validation 的支持。请改用 skip_checks (Django 1.7 中添加)来代替。
  • 现在,在指定的夹具文件未找到时,loaddata 将引发一个 CommandError,而不是显示警告。
  • 现在,最好调用 LogEntry.get_change_message() 方法来获取日志条目的消息,而不是直接访问 LogEntry.change_message 属性,这样可以提供当前语言的消息。
  • 如果指定了不存在的 template_name,默认错误视图现在会引发 TemplateDoesNotExist 异常。
  • SelectSelectMultiple 小部件的 render() 方法中未使用的 choices 关键字参数已被移除。 render_options() 方法中的 choices 参数也已被移除,现在 selected_choices 是第一个参数。
  • 现在,在支持可延迟约束的数据库上运行的违反可延迟数据库约束的测试将会出现错误。
  • 内置管理命令现在使用 options 中键的索引,例如 options['verbosity'],而不是 options.get(),并且不再执行任何类型强制转换。如果你正在使用 Command.execute() 调用命令(绕过设置默认值的参数解析器),而不是 call_command(),这可能会导致问题。不要调用 Command.execute(),而是将命令对象作为第一个参数传递给 call_command()
  • ModelBackendRemoteUserBackend 现在会拒绝不活跃的用户。这意味着不活跃的用户无法登录,如果将他们从 is_active=True 更改为 False,他们将被登出。如果需要以前的行为,请在 AUTHENTICATION_BACKENDS 中使用新的 AllowAllUsersModelBackendAllowAllUsersRemoteUserBackend
  • 鉴于先前的更改,测试客户端的 login() 方法不再始终拒绝不活跃的用户,而是将这个决定委托给身份验证后端。 force_login() 也将决定委托给身份验证后端,因此如果你使用默认的后端,你需要使用一个活跃的用户。
  • django.views.i18n.set_language() 现在可以为 AJAX 请求返回一个 204 状态码。
  • RangeFieldbase_field 属性现在是一个字段类型,而不是字段的实例。如果你创建了 RangeField 的自定义子类,你应该更改 base_field 属性。
  • 现在,中间件类在服务器启动时初始化,而不是在第一个请求期间。
  • 如果你在自定义用户模型中重写了 is_authenticated()is_anonymous() 方法,你必须将它们转换为属性或属性,如 弃用说明 中所述。
  • 当使用 ModelAdmin.save_as=True 时,”Save as new” 按钮现在会重定向到新对象的修改视图,而不是模型的变更列表。如果你需要之前的行为,请将新的 ModelAdmin.save_as_continue 属性设置为 False
  • 必填的表单字段现在具有 required HTML 属性。如果要禁用它,请将 Form.use_required_attribute 属性设置为 False。如果不想要浏览器验证,还可以在 <form> 中添加 novalidate 属性。如果要在自定义小部件上禁用 required 属性,请重写 Widget.use_required_attribute() 方法。
  • WSGI 处理程序不再从 HEAD 请求或具有 status_code 为 100-199、204 或 304 的响应中删除内容。大多数 Web 服务器已经实现了这种行为。使用 Django 测试客户端检索的响应仍然会应用这些 “响应修复”。
  • Model.__init__() 现在会将 django.db.models.DEFERRED 作为延迟字段的值。
  • Model._deferred 属性在使用 QuerySet.defer()only() 时动态模型类被移除。
  • Storage.save() 不再将 '\' 替换为 '/'。这个行为已经移到 FileSystemStorage 中,因为这是一个与存储相关的具体实现细节。如果有自定义存储实现依赖这个行为的 Windows 用户,需要在自定义存储的 save() 方法中实现这个行为。
  • 私有的 FileField 方法 get_directory_name()get_filename() 不再被调用(并且现在已被弃用),这对于在自定义字段上重写这些方法的用户来说是一个不兼容的变更。要适应这种代码,可以重写 FileField.generate_filename()Storage.generate_filename()。也可能可以使用 upload_to
  • AdminEmailHandler 发送的邮件主题不再在 989 个字符处截断。如果你依赖于有限的长度,请自行截断主题。
  • 私有表达式 django.db.models.expressions.DateDateTime 已被移除。新的 Trunc 表达式提供了相同的功能。
  • 模型实例中的 _base_manager_default_manager 属性已被移除。您仍然可以在模型类上访问它们。
  • 在模型实例上访问已删除的字段(例如,在执行 del obj.field 后)将重新加载字段的值,而不会引发 AttributeError
  • 如果您子类化了 AbstractBaseUser 并覆盖了 clean() 方法,请确保在其中调用 super()。现在在新的 AbstractBaseUser.clean() 方法中调用了 AbstractBaseUser.normalize_username()
  • 私有 API django.forms.models.model_to_dict() 现在返回一个查询集而不是 ManyToManyField 的主键列表。
  • 如果安装了 django.contrib.staticfiles,那么 static 模板标签将使用 staticfiles 存储来构建 URL,而不仅仅是与 STATIC_ROOT 连接。这种新方法对URL进行了编码,可能在包含路径中的片段的情况下存在向后不兼容性,例如 {% static 'img.svg#fragment' %},因为 # 被编码为 %23。要进行适应,将片段移到模板标签之外:{% static 'img.svg' %}#fragment
  • USE_L10NTrue 时,如果没有指定格式字符串,则 datetime 过滤器现在会应用本地化。它们将使用活动区域设置中的 DATE_FORMATTIME_FORMAT 指示符,而不是同名的设置。

在 1.10 中被废弃的功能

直接分配给反向外键或多对多关系

不要使用直接分配来分配相关对象:

  1. >>> new_list = [obj1, obj2, obj3]
  2. >>> e.related_set = new_list

使用 Django 1.9 中添加的 set() 方法:

  1. >>> e.related_set.set([obj1, obj2, obj3])

这可以避免因隐式保存导致的分配混淆。

非时区感知的 Storage API

旧的、非时区感知的方法 accessed_time(), created_time(), 和 modified_time() 已被弃用,推荐使用新的 get_*_time() 方法。

第三方存储后端应该实现新的方法并将旧的方法标记为弃用。在此之前,基础的 Storage 类上的新的 get_*_time() 方法将根据需要将来自旧方法的 datetime 转换并在这样做时发出弃用警告。

只要第三方存储后端希望支持早期版本的 Django,它们就可以保留旧方法。

django.contrib.gis

  • GEOSGeometryget_srid()set_srid() 方法已被弃用,推荐使用 srid 属性。
  • Pointget_x(), set_x(), get_y(), set_y(), get_z(), 和 set_z() 方法已被弃用,推荐使用 x, y, 和 z 属性。
  • Pointget_coords()set_coords() 方法已被弃用,推荐使用 tuple 属性。
  • MultiPolygoncascaded_union 属性已被弃用,推荐使用 unary_union 属性。
  • django.contrib.gis.utils.precision_wkt() 函数已被弃用,推荐使用 WKTWriter

CommaSeparatedIntegerField 模型字段

CommaSeparatedIntegerField 已被弃用,推荐使用 CharField 并配合 validate_comma_separated_integer_list() 验证器使用:

  1. from django.core.validators import validate_comma_separated_integer_list
  2. from django.db import models
  3. class MyModel(models.Model):
  4. numbers = models.CharField(..., validators=[validate_comma_separated_integer_list])

如果您使用的是 Oracle 数据库,CharField 使用不同的数据库字段类型(NVARCHAR2)而不是 CommaSeparatedIntegerFieldVARCHAR2)。根据您的数据库设置,这可能意味着相同内容的不同编码,从而导致相同内容的不同字节长度。如果您存储的值长于 NVARCHAR2 的 4000 字节限制,您应该改用 TextFieldNCLOB)。在这种情况下,如果您有任何按字段分组的查询(例如,使用聚合注释模型或使用 distinct()),您需要更改它们(以延迟字段)。

假设以下模型:

  1. from django.db import models
  2. class Foo(models.Model):
  3. pass
  4. class Bar(models.Model):
  5. foo = models.ForeignKey(Foo)
  6. class Meta:
  7. default_related_name = "bars"

在较旧的版本中,不能将 default_related_name 用作查询查找。这已经得到修复,并且不再支持旧的查找名称。例如,由于在模型 Bar 中设置了 default_related_name,所以不再使用模型名称 bar 作为查找:

  1. >>> bar = Bar.objects.get(pk=1)
  2. >>> Foo.objects.get(bar=bar)

使用 default_related_name 中的 bars

  1. >>> Foo.objects.get(bars=bar)

__search 查询查找

search 查询查找已被弃用,它仅支持 MySQL,并且功能非常有限。请将其替换为自定义查询查找:

  1. from django.db import models
  2. class Search(models.Lookup):
  3. lookup_name = "search"
  4. def as_mysql(self, compiler, connection):
  5. lhs, lhs_params = self.process_lhs(compiler, connection)
  6. rhs, rhs_params = self.process_rhs(compiler, connection)
  7. params = lhs_params + rhs_params
  8. return "MATCH (%s) AGAINST (%s IN BOOLEAN MODE)" % (lhs, rhs), params
  9. models.CharField.register_lookup(Search)
  10. models.TextField.register_lookup(Search)

使用 User.is_authenticated()User.is_anonymous() 作为方法。

AbstractBaseUserAnonymousUser 类的 is_authenticated()is_anonymous() 方法现在已经变成属性。它们在 Django 2.0 之前仍然作为方法使用,但在 Django 中的所有用法现在都使用属性访问。

例如,如果您使用 AuthenticationMiddleware 并想知道用户当前是否已登录,您可以使用以下方式:

  1. if request.user.is_authenticated:
  2. ... # Do something for logged-in users.
  3. else:
  4. ... # Do something for anonymous users.

而不是 request.user.is_authenticated()

此更改可以避免在您忘记调用方法时意外泄露信息,例如:

  1. if request.user.is_authenticated:
  2. return sensitive_information

如果你在自定义用户模型中重写了这些方法,你必须将它们更改为属性或特性。

Django 使用一个 CallableBool 对象,以使这些属性同时可以作为属性和方法工作。因此,在弃用期结束之前,您不能使用 is 运算符比较这些属性。也就是说,以下操作不起作用:

  1. if request.user.is_authenticated is True:
  2. ...

如果您定义了一个通过 prefetch_related() 可用的自定义管理器类,您必须确保它定义了一个 _apply_rel_filters() 方法。

这个方法必须接受一个 QuerySet 实例作为其唯一参数,并返回与管理器绑定的模型实例的经过筛选的查询集的版本。

django.utils.safestring 的 “escape” 部分

mark_for_escaping() 函数以及它使用的类:EscapeDataEscapeBytesEscapeTextEscapeStringEscapeUnicode 已被弃用。

因此,escape 过滤器的 “懒惰” 行为(无论在过滤器链的哪个位置,它始终作为最后一个过滤器应用)已被弃用。在 Django 2.0 中,该过滤器将立即应用 conditional_escape()

Manager.use_for_related_fields 已被弃用,推荐在模型上设置 Meta.base_manager_name

在 Django 2.0 中,模型 Manager 的继承将遵循 MRO 继承规则,改变了当前的行为,其中在非抽象基类上定义的管理器不会被子类继承。如果您有任何受影响的管理器,将会引发一个带有关于如何调整代码的弃用警告。您可以在子类上重新声明来自抽象模型的管理器,以覆盖来自具体模型的管理器,或者您可以设置模型的 Meta.manager_inheritance_from_future=True 选项,以选择新的继承行为。

在弃用期间,即使设置了 base_manager_name,也会尊重 use_for_related_fields 并引发警告。这允许第三方代码在过渡到新的 API 时保留传统行为。可以通过在管理器上设置 silence_use_for_related_fields_deprecation=True 来消除警告。

杂项

  • makemigrations --exit 选项已被弃用,推荐使用 makemigrations —check 选项。
  • django.utils.functional.allow_lazy() 已被弃用,推荐使用新的 keep_lazy() 函数,它可以使用更自然的装饰器语法。
  • shell --plain 选项已被弃用,推荐使用 -i python--interface python
  • django.core.urlresolvers 模块导入已被弃用,推荐使用其新位置 django.urls
  • 模板中的 Context.has_key() 方法已被弃用,推荐使用 in
  • Model._meta 的私有属性 virtual_fields 已被弃用,推荐使用 private_fields
  • Field.contribute_to_class() 中的私有关键字参数 virtual_onlyModel._meta.add_field() 中的 virtual 已被弃用,分别推荐使用 private_onlyprivate
  • javascript_catalog()json_catalog() 视图已被弃用,推荐使用基于类的视图 JavaScriptCatalogJSONCatalog
  • 在多表继承中,将一个 OneToOneField 隐式提升为 parent_link 已被弃用。应该在这些字段上添加 parent_link=True
  • 私有 API Widget._format_value() 已被公开,并重命名为 format_value()。旧名称将在弃用期间继续工作。
  • 私有的 FileField 方法 get_directory_name()get_filename() 已被弃用,推荐在 Storage.generate_filename() 中执行这项工作。
  • 使用 settings.MIDDLEWARE_CLASSES 的旧式中间件已被弃用。请 适应旧的自定义中间件 并使用新的 MIDDLEWARE 设置。

在 1.10 中移除的功能

这些功能已经完成了弃用周期,并在 Django 1.10 中被移除。有关详细信息,包括如何移除这些功能的用法,请参阅 在 1.8 中被废弃的功能

  • 不再支持直接调用 SQLCompiler 作为调用其 quote_name_unless_alias 方法的别名。
  • cyclefirstof 模板标签已从 future 模板标签库中移除。
  • django.conf.urls.patterns() 已被移除。
  • 不再支持 prefix 参数用于 django.conf.urls.i18n.i18n_patterns()
  • SimpleTestCase.urls 已被移除。
  • 在模板标签 for 中使用不正确数量的解包值将引发异常,而不是默默失败。
  • 使用点分隔的 Python 路径反向 reverse() URL 的能力已被移除。
  • 使用点分隔的 Python 路径设置 LOGIN_URLLOGIN_REDIRECT_URL 的能力已被移除。
  • 自定义管理命令不再支持 optparse
  • django.core.management.NoArgsCommand 已被移除。
  • django.core.context_processors 模块已被移除。
  • django.db.models.sql.aggregates 模块已被移除。
  • django.contrib.gis.db.models.sql.aggregates 模块已被移除。
  • 以下 django.db.sql.query.Query 的方法和属性已被移除:
    • 属性:aggregatesaggregate_select 将被移除。
    • 方法:add_aggregateset_aggregate_maskappend_aggregate_mask 将被移除。
  • django.template.resolve_variable 已被移除。
  • 以下私有 API 已从 django.db.models.options.OptionsModel._meta)中移除:
    • get_field_by_name()
    • get_all_field_names()
    • get_fields_with_model()
    • get_concrete_fields_with_model()
    • get_m2m_with_model()
    • get_all_related_objects()
    • get_all_related_objects_with_model()
    • get_all_related_many_to_many_objects()
    • get_all_related_m2m_objects_with_model()
  • django.forms.RegexFielderror_message 参数已被移除。
  • unordered_list 过滤器不再支持旧式列表。
  • 不再支持将字符串 view 参数传递给 url()
  • django.forms.Form._has_changed() 重命名为 has_changed() 的向后兼容性修补程序已被移除。
  • removetags 模板过滤器已被移除。
  • django.utils.html 中的 remove_tags()strip_entities() 函数已被移除。
  • django.contrib.auth.views.password_reset() 中的 is_admin_site 参数已被移除。
  • django.db.models.field.subclassing.SubfieldBase 已被移除。
  • django.utils.checksums 已被移除。
  • django.contrib.admin.helpers.InlineAdminForm 上的 original_content_type_id 属性已被移除。
  • 允许不为其 form_class 参数定义默认值的 FormMixin.get_form() 的向后兼容性修复已被移除。
  • 以下设置已被移除,您必须升级到 TEMPLATES 设置:
    • ALLOWED_INCLUDE_ROOTS
    • TEMPLATE_CONTEXT_PROCESSORS
    • TEMPLATE_DEBUG
    • TEMPLATE_DIRS
    • TEMPLATE_LOADERS
    • TEMPLATE_STRING_IF_INVALID
  • 向后兼容的别名 django.template.loader.BaseLoader 已被移除。
  • get_template()select_template() 返回的 Django 模板对象不再在其 render() 方法中接受 Context
  • Template response APIs 强制使用 dict 和依赖后端的模板对象,而不再使用 ContextTemplate
  • 以下函数和类的 current_app 参数已被移除:
    • django.shortcuts.render()
    • django.template.Context()
    • django.template.RequestContext()
    • django.template.response.TemplateResponse()
  • 以下函数的 dictionarycontext_instance 参数已被移除:
    • django.shortcuts.render()
    • django.shortcuts.render_to_response()
    • django.template.loader.render_to_string()
  • 以下函数的 dirs 参数已被移除:
    • django.template.loader.get_template()
    • django.template.loader.select_template()
    • django.shortcuts.render()
    • django.shortcuts.render_to_response()
  • 会话验证现在已启用,无论是否在 MIDDLEWARE_CLASSES 中包含 'django.contrib.auth.middleware.SessionAuthenticationMiddleware'SessionAuthenticationMiddleware 不再有任何用途,可以从 MIDDLEWARE_CLASSES 中删除。为了方便那些没有阅读此说明的用户,它被保留为一个存根,直到 Django 2.0。
  • 私有属性 django.db.models.Field.related 已被移除。
  • migrate 管理命令的 --list 选项已被移除。
  • ssi 模板标签已被移除。
  • 不再支持 if 模板标签中的 = 比较运算符。
  • 允许在不带 max_length 参数的情况下定义 Storage.get_available_name()Storage.save() 的向后兼容性修复已被移除。
  • ModelFormMixin.success_url 中移除了对旧式 %(<foo>)s 语法的支持。
  • 移除了``GeoQuerySet`` 聚合方法 collect(), extent(), extent3d(), make_line(), 和 unionagg()
  • 在创建内容类型实例时不再支持指定 ContentType.name 的能力。
  • 不再支持旧的 allow_migrate 签名。
  • 移除了使用逗号分隔参数的 {% cycle %} 语法的支持。
  • Signer 在提供无效的分隔符时发出的警告现在是一个 ValueError