# Django 5.2.8 documentation

# 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` 查找以及 `TrigramSimilarity` 和 `TrigramDistance` 表达式。

### 新式中间件

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

### 官方支持 Unicode 用户名

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

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

自定义用户模型可以使用新的 `ASCIIUsernameValidator` 或 `UnicodeUsernameValidator`。

### 次要特性

#### `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()` 视图，允许重定向已经经过身份验证的用户访问登录页面。

- 新的 `AllowAllUsersModelBackend` 和 `AllowAllUsersRemoteUserBackend` 忽略了 `User.is_active` 的值，而 `ModelBackend` 和 `RemoteUserBackend` 现在拒绝不活动的用户。

#### `django.contrib.gis`

- 距离查找 现在接受表达式作为距离值参数。

- 新的 `GEOSGeometry.unary_union` 属性计算了此几何对象的所有元素的并集。

- 新增了 `GEOSGeometry.covers()` 二元谓词。

- 新增了 `GDALBand.statistics()` 方法以及 `mean` 和 `std` 属性。

- 在 SpatiaLite 上新增了对 `MakeLine` 聚合和 `GeoHash` 函数的支持。

- 在 MySQL 上新增了对 `Difference`、`Intersection` 和 `SymDifference` 函数的支持。

- 新增支持实例化空的 GEOS 几何对象。

- `WKTWriter` 的新属性 `trim` 和 `precision` 允许控制 WKT 中坐标的小数部分的输出。

- 新增了 `LineString.closed` 和 `MultiLineString.closed` 属性。

- 如果没有指定特定字段， GeoJSON 序列化程序 现在会在 `properties` 字典中输出对象的主键。

- 现在可以在 `GDALBand.data()` 方法上复制输入数据。可以高效地使用重复的值更新带数据。

- 新增了数据库函数 `IsValid` 和 `MakeValid`，以及 `isvalid` 查找，都用于 PostGIS。这允许在数据库端对无效的几何对象进行过滤和修复。

- 新增了所有 空间查找 的栅格支持。

#### `django.contrib.postgres`

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

#### `django.contrib.sessions`

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

#### `django.contrib.sites`

- `Site` 模型现在支持 自然键。

#### `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_VIEW`，`views.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()` 创建的对象上设置主键。

- 为各种表达式（`Func`、`When`、`Case` 和 `OrderBy`）的 `as_sql()` 方法添加了关键字参数，允许数据库后端在不更改 `self` 的情况下自定义它们，这在使用不同的数据库后端时不安全。参见 `Func.as_sql()` 的 `arg_joiner` 和 `**extra_context` 参数的示例。

#### 文件存储

- 存储后端现在提供一个时区感知的 API，具有新的方法 `get_accessed_time()`、`get_created_time()` 和 `get_modified_time()`。如果 `USE_TZ` 为 `True`，则它们返回一个时区感知的 `datetime`，否则返回本地时区的非时区感知的 `datetime`。

- 新的 `Storage.generate_filename()` 方法使得更容易实现不使用以前在 `FileField` 中的 `os.path` 调用的自定义存储。

#### 表单

- 如果安装了 `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 前缀的情况下访问默认语言。

- 现在，当在 `POST` 或 `GET` 中没有 `next` 参数时，`set_language()` 对于 AJAX 请求会返回 204 状态码（No Content）。

- `JavaScriptCatalog` 和 `JSONCatalog` 类视图取代了不推荐使用的 `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` 对象。

- 在 `RunSQL` 和 `RunPython` 操作中添加了 `elidable` 参数，以允许在压缩迁移时删除它们。

- 通过在 `Migration` 上设置 `atomic` 属性，添加了对 非原子迁移 的支持。

- `migrate` 和 `makemigrations` 命令现在会 检查一致的迁移历史。如果它们发现某些已应用的迁移存在未应用的依赖项，将会引发 `InconsistentMigrationHistory` 异常。

- `pre_migrate()` 和 `post_migrate()` 信号现在会分发它们的迁移 `plan` 和 `apps`。

#### 模型

- 来自代理模型的反向外键现在会传播到它们的具体类。指向代理模型的 `ForeignKey` 所附加的反向关系现在可以作为描述符在代理模型类上访问，并且可以在查询集过滤中引用。

- 新的 `Field.rel_db_type()` 方法返回了诸如 `ForeignKey` 和 `OneToOneField` 这样指向另一个字段的字段的数据库列数据类型。

- `Func` 添加了 `arity` 类属性。此属性可用于设置函数接受的参数数量。

- 新增了 `BigAutoField`，它的行为类似于 `AutoField`，但它保证适合于范围从 `1` 到 `9223372036854775807` 的数字。

- 可以不带任何参数调用 `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_name` 和 `Meta.default_manager_name` 选项允许分别控制 `_base_manager` 和 `_default_manager`。

#### 请求和响应

- 在调试视图中添加了 `request.user`。

- Added `HttpResponse` methods `readable()` and `seekable()` to make an instance a stream-like object and allow wrapping it with `io.TextIOWrapper`.

- 添加了 `HttpRequest.content_type` 和 `content_params` 属性，这些属性从 `CONTENT_TYPE` 标头中解析而来。

- `request.COOKIES` 的解析器被简化，以更好地匹配浏览器的行为。`request.COOKIES` 现在可以包含根据 RFC 6265 无效但可以通过 `document.cookie` 设置的 cookie。

#### 序列化

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

#### 模板

- 在 `DjangoTemplates` 后端和 `Engine` 类中添加了 `autoescape` 选项。

- 在 `if` 标签中添加了 `is` 和 `is not` 比较运算符。

- 允许使用 `dictsort` 根据指定索引处的元素对列表中的列表进行排序。

- `debug()` 上下文处理器包含了所有数据库别名的查询，而不仅仅是默认别名。

- 对 `extends` 和 `include` 模板标签的字符串参数添加了相对路径支持。

#### 测试

- 为了更好地捕获错误，`TestCase` 现在在每个测试结束时检查可延迟的数据库约束。

- 测试和测试用例可以被 标记为标签 并可以使用新的 `test --tag` 和 `test --exclude-tag` 选项进行选择性运行。

- 即使 `django.contrib.sessions` 不在 `INSTALLED_APPS` 中，您现在也可以使用测试客户端登录并使用会话。

#### URLs

- An addition in `django.setup()` allows URL resolving that happens outside of the request/response cycle (e.g. in management commands and standalone scripts) to take `FORCE_SCRIPT_NAME` into account when it is set.

#### 验证器

- `URLValidator` 现在将域名标签的长度限制为 63 个字符，域名的总长度限制为 253 个字符，符合 RFC 1034 的规定。

- `int_list_validator()` 现在接受一个可选的布尔参数 `allow_negative`，默认为 `False`，以允许负整数。

## 1.10 中的不向后兼容的变更

Warning

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

### 数据库后端 API

- GIS 的 `AreaField` 使用一个未指定的底层数字类型，实际上可以是任何 Python 数值类型。从数据库中检索到的 `decimal.Decimal` 值现在被转换为 `float`，以便更容易将它们与 GIS 库使用的值结合在一起。

- 为了启用时间减法，您必须将数据库功能标志 `supports_temporal_subtraction` 设置为 `True`，并实现 `DatabaseOperations.subtract_temporals()` 方法。该方法应返回计算``lhs`` 和 `rhs` 参数之间差异的微秒数所需的 SQL 和参数，其数据类型用于存储 `DurationField`。

### `select_related()` 禁止嵌套关系的非关系字段。

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

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

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

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

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

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

### `AbstractUser.username` 的 `max_length` 增加到了 150。

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

We considered an increase to 254 characters to more easily allow the use of email addresses (which are limited to 254 characters) as usernames but rejected it due to a MySQL limitation. When using the `utf8mb4` encoding (recommended for proper Unicode support), MySQL can only create unique indexes with 191 characters by default. Therefore, if you need a longer length, please use a custom user model.

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

    from django.contrib.auth.forms import UserCreationForm

    class MyUserCreationForm(UserCreationForm):
        username = forms.CharField(
            max_length=30,
            help_text="Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.",
        )

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

    from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
    from django.contrib.auth.models import User

    class UserAdmin(BaseUserAdmin):
        add_form = MyUserCreationForm

    admin.site.unregister(User)
    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 的日志配置或使用自己的配置覆盖了它，如果您想看到该输出，您需要添加适当的日志配置：

    LOGGING = {
        # ...
        "formatters": {
            "django.server": {
                "()": "django.utils.log.ServerFormatter",
                "format": "[%(server_time)s] %(message)s",
            }
        },
        "handlers": {
            "django.server": {
                "level": "INFO",
                "class": "logging.StreamHandler",
                "formatter": "django.server",
            },
        },
        "loggers": {
            "django.server": {
                "handlers": ["django.server"],
                "level": "INFO",
                "propagate": False,
            }
        },
    }

### `auth.CustomUser` 和 `auth.ExtensionUser` 测试模型已被移除。

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

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

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

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

在旧版本中，将 `None` 分配给非空 `ForeignKey` 或 `OneToOneField` 会引发 `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 作为默认密码哈希器。

If you have an old Django project with MD5 or SHA1 (even salted) encoded passwords, be aware that these can be cracked fairly easily with today's hardware. To make Django users acknowledge continued use of weak hashers, the following hashers are removed from the default `PASSWORD_HASHERS` setting:

- `"django.contrib.auth.hashers.SHA1PasswordHasher"`

- `"django.contrib.auth.hashers.MD5PasswordHasher"`

- `"django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher"`

- `"django.contrib.auth.hashers.UnsaltedMD5PasswordHasher"`

- `"django.contrib.auth.hashers.CryptPasswordHasher"`

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

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

    from django.contrib.auth import get_user_model

    User = get_user_model()

    # Unsalted MD5/SHA1:
    User.objects.filter(password__startswith="md5$$")
    User.objects.filter(password__startswith="sha1$$")
    # Salted MD5/SHA1:
    User.objects.filter(password__startswith="md5$").exclude(password__startswith="md5$$")
    User.objects.filter(password__startswith="sha1$").exclude(password__startswith="sha1$$")
    # Crypt hasher:
    User.objects.filter(password__startswith="crypt$$")

    from django.db.models import CharField
    from django.db.models.functions import Length

    CharField.register_lookup(Length)
    # Unsalted MD5 passwords might not have an 'md5$$' prefix:
    User.objects.filter(password__length=32)

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

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

    from django.db.models import Field
    from django.db.models.lookups import Exact

    class MyField(Field): ...

    class MyFieldExact(Exact):
        def get_prep_lookup(self):
            # do_custom_stuff_for_myfield
            ...

    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 参数的数量受到限制。

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

- `DATA_UPLOAD_MAX_MEMORY_SIZE` 限制请求主体的大小。文件上传不计入此限制。

- `DATA_UPLOAD_MAX_NUMBER_FIELDS` 限制解析的 GET/POST 参数的数量。

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

### 杂项

- `QuerySet` 的 `repr()` 现在在调试时会包装在 `<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` 异常。

- `Select` 和 `SelectMultiple` 小部件的 `render()` 方法中未使用的 `choices` 关键字参数已被移除。 `render_options()` 方法中的 `choices` 参数也已被移除，现在 `selected_choices` 是第一个参数。

- 现在，在支持可延迟约束的数据库上运行的违反可延迟数据库约束的测试将会出现错误。

- 内置管理命令现在使用 `options` 中键的索引，例如 `options['verbosity']`，而不是 `options.get()`，并且不再执行任何类型强制转换。如果你正在使用 `Command.execute()` 调用命令（绕过设置默认值的参数解析器），而不是 `call_command()`，这可能会导致问题。不要调用 `Command.execute()`，而是将命令对象作为第一个参数传递给 `call_command()`。

- `ModelBackend` 和 `RemoteUserBackend` 现在会拒绝不活跃的用户。这意味着不活跃的用户无法登录，如果将他们从 `is_active=True` 更改为 `False`，他们将被登出。如果需要以前的行为，请在 `AUTHENTICATION_BACKENDS` 中使用新的 `AllowAllUsersModelBackend` 或 `AllowAllUsersRemoteUserBackend`。

- In light of the previous change, the test client's `login()` method no longer always rejects inactive users but instead delegates this decision to the authentication backend. `force_login()` also delegates the decision to the authentication backend, so if you're using the default backends, you need to use an active user.

- `django.views.i18n.set_language()` 现在可以为 AJAX 请求返回一个 204 状态码。

- The `base_field` attribute of `RangeField` is now a type of field, not an instance of a field. If you have created a custom subclass of `RangeField`, you should change the `base_field` attribute.

- 现在，中间件类在服务器启动时初始化，而不是在第一个请求期间。

- 如果你在自定义用户模型中重写了 `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.Date` 和 `DateTime` 已被移除。新的 `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_L10N` 为 `True` 时，如果没有指定格式字符串，则 `date` 和 `time` 过滤器现在会应用本地化。它们将使用活动区域设置中的 `DATE_FORMAT` 和 `TIME_FORMAT` 指示符，而不是同名的设置。

## 在 1.10 中被废弃的功能

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

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

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

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

    >>> 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`

- `GEOSGeometry` 的 `get_srid()` 和 `set_srid()` 方法已被弃用，推荐使用 `srid` 属性。

- `Point` 的 `get_x()`, `set_x()`, `get_y()`, `set_y()`, `get_z()`, 和 `set_z()` 方法已被弃用，推荐使用 `x`, `y`, 和 `z` 属性。

- `Point` 的 `get_coords()` 和 `set_coords()` 方法已被弃用，推荐使用 `tuple` 属性。

- `MultiPolygon` 的 `cascaded_union` 属性已被弃用，推荐使用 `unary_union` 属性。

- `django.contrib.gis.utils.precision_wkt()` 函数已被弃用，推荐使用 `WKTWriter`。

### `CommaSeparatedIntegerField` 模型字段

`CommaSeparatedIntegerField` 已被弃用，推荐使用 `CharField` 并配合 `validate_comma_separated_integer_list()` 验证器使用：

    from django.core.validators import validate_comma_separated_integer_list
    from django.db import models

    class MyModel(models.Model):
        numbers = models.CharField(..., validators=[validate_comma_separated_integer_list])

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

### 当设置了 `default_related_name` 时，可以使用模型名称作为查询查找。

假设以下模型：

    from django.db import models

    class Foo(models.Model):
        pass

    class Bar(models.Model):
        foo = models.ForeignKey(Foo)

        class Meta:
            default_related_name = "bars"

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

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

使用 `default_related_name` 中的 `bars`：

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

### `__search` 查询查找

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

    from django.db import models

    class Search(models.Lookup):
        lookup_name = "search"

        def as_mysql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return "MATCH (%s) AGAINST (%s IN BOOLEAN MODE)" % (lhs, rhs), params

    models.CharField.register_lookup(Search)
    models.TextField.register_lookup(Search)

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

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

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

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

而不是 `request.user.is_authenticated()`。

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

    if request.user.is_authenticated:
        return sensitive_information

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

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

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

### 通过 `prefetch_related` 可用的自定义管理器类必须定义一个 `_apply_rel_filters()` 方法。

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

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

### `django.utils.safestring` 的 "escape" 部分

`mark_for_escaping()` 函数以及它使用的类：`EscapeData`、`EscapeBytes`、`EscapeText`、`EscapeString` 和 `EscapeUnicode` 已被弃用。

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

### `Manager.use_for_related_fields` 和继承方面的变化

`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_only` 和 `Model._meta.add_field()` 中的 `virtual` 已被弃用，分别推荐使用 `private_only` 和 `private`。

- `javascript_catalog()` 和 `json_catalog()` 视图已被弃用，推荐使用基于类的视图 `JavaScriptCatalog` 和 `JSONCatalog`。

- 在多表继承中，将一个 `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` 方法的别名。

- `cycle` 和 `firstof` 模板标签已从 `future` 模板标签库中移除。

- `django.conf.urls.patterns()` 已被移除。

- 不再支持 `prefix` 参数用于 `django.conf.urls.i18n.i18n_patterns()`。

- `SimpleTestCase.urls` 已被移除。

- 在模板标签 `for` 中使用不正确数量的解包值将引发异常，而不是默默失败。

- 使用点分隔的 Python 路径反向 `reverse()` URL 的能力已被移除。

- 使用点分隔的 Python 路径设置 `LOGIN_URL` 和 `LOGIN_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` 的方法和属性已被移除：

  - 属性：`aggregates` 和 `aggregate_select` 将被移除。

  - 方法：`add_aggregate`、`set_aggregate_mask` 和 `append_aggregate_mask` 将被移除。

- `django.template.resolve_variable` 已被移除。

- 以下私有 API 已从 `django.db.models.options.Options` （`Model._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.RegexField` 的 `error_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` 已被移除。

- Django template objects returned by `get_template()` and `select_template()` no longer accept a `Context` in their `render()` method.

- Template response APIs 强制使用 `dict` 和依赖后端的模板对象，而不再使用 `Context` 和 `Template`。

- 以下函数和类的 `current_app` 参数已被移除：

  - `django.shortcuts.render()`

  - `django.template.Context()`

  - `django.template.RequestContext()`

  - `django.template.response.TemplateResponse()`

- 以下函数的 `dictionary` 和 `context_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`。