---
title: "Django 1.9 版本发行说明"
version: 5.1
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/5.1/releases/1.9/
canonical: https://djangodocs.dev/zh-hans/5.1/releases/1.9/
---
# Django 1.9 版本发行说明

*2015 年 12 月 1 日*

欢迎使用 Django 1.9 ！

这些发布说明包括 [新特性](#whats-new-1-9)，以及从 Django 1.8 或更早版本升级时需要注意的一些 [不兼容变更](#backwards-incompatible-1-9)。我们已经 [删除了一些已经完成了其废弃周期的功能](#removed-features-1-9)，并且已经 [开始废弃某些功能](#deprecated-features-1-9)。

如果你要更新现有的项目，请看 [如何将 Django 更新至新的版本](/zh-hans/5.1/howto/upgrade-version/) 指南。

## Python 兼容性

Django 1.9 需要 Python 2.7、3.4 或 3.5。我们 **强烈建议** 并且只官方支持每个系列的最新版本。

Django 1.8 系列是最后一个支持 Python 3.2 和 3.3 的版本。

## Django 1.9 的新特性

### 事务提交后执行操作

新的 [`on_commit()`](/zh-hans/5.1/topics/db/transactions/#django.db.transaction.on_commit) 钩子允许在数据库事务成功提交后执行操作。这对于执行诸如发送通知电子邮件、创建排队任务或使缓存无效等任务非常有用。

这个功能已经被集成到 Django 中，之前是作为 [django-transaction-hooks](https://pypi.org/project/django-transaction-hooks/) 包的一部分。

### 密码验证

Django 现在提供密码验证功能，以帮助防止用户使用弱密码。该验证已集成在包含的密码更改和重置表单中，并且可以简单地集成到任何其他代码中。验证由一个或多个验证器执行，可以在新的 [`AUTH_PASSWORD_VALIDATORS`](/zh-hans/5.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS) 设置中配置。

Django 中包含了四个验证器，可以强制实施最小长度、将密码与用户的属性进行比较（如姓名）、确保密码不全为数字，或者检查是否在包含的常见密码列表中。您可以组合多个验证器，并且某些验证器具有自定义配置选项。例如，您可以选择提供自定义的常见密码列表。每个验证器都提供帮助文本，向用户解释其要求。

默认情况下，不执行任何验证，所有密码都会被接受，因此如果您不设置 [`AUTH_PASSWORD_VALIDATORS`](/zh-hans/5.1/ref/settings/#std-setting-AUTH_PASSWORD_VALIDATORS)，您将不会看到任何更改。在使用默认 [`startproject`](/zh-hans/5.1/ref/django-admin/#django-admin-startproject) 模板创建的新项目中，已启用一组简单的验证器。要在您的项目中为包含的认证表单启用基本验证，您可以设置如下配置，例如：

```
AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]
```

有关更多详细信息，请参阅 [密码验证](/zh-hans/5.1/topics/auth/passwords/#password-validation)。

### 用于基于类的视图的权限混合类

Django 现在包含了一些 mixin 类，如 [`AccessMixin`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.AccessMixin)、[`LoginRequiredMixin`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.LoginRequiredMixin)、[`PermissionRequiredMixin`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.PermissionRequiredMixin) 和 [`UserPassesTestMixin`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin)，用于为基于类的视图提供与 `django.contrib.auth.decorators` 相同的功能。这些 mixin 类来自或受到了 [django-braces](https://django-braces.readthedocs.io/en/latest/index.html) 项目的启发。

尽管如此，在 Django 和 `django-braces`' 的实现之间存在一些差异：

- [`raise_exception`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.AccessMixin.raise_exception) 属性只能为 `True` 或 `False`。不支持自定义异常或可调用对象。
- [`handle_no_permission()`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.AccessMixin.handle_no_permission) 方法不接受 `request` 参数。当前请求可在 `self.request` 中获取。
- [`UserPassesTestMixin`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.UserPassesTestMixin) 的自定义 `test_func()` 不接受 `user` 参数。当前用户可在 `self.request.user` 中获取。
- [`permission_required`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.PermissionRequiredMixin) 属性支持一个字符串（定义一个权限）或一个字符串的列表/元组（定义多个权限），这些权限需要满足才能授予访问权限。
- 新的 [`permission_denied_message`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.mixins.AccessMixin.permission_denied_message) 属性允许传递消息给 `PermissionDenied` 异常。

### `contrib.admin` 中的新样式

管理员界面采用了现代的扁平设计，使用新的 SVG 图标，在高分辨率屏幕上效果非常好。它仍然在 [YUI's A-grade](https://github.com/yui/yui3/wiki/Graded-Browser-Support) 浏览器中提供了完全功能的体验。较旧的浏览器可能会有不同程度的优雅降级。

### 并行运行测试

[`test`](/zh-hans/5.1/ref/django-admin/#django-admin-test) 命令现在支持 [`--parallel`](/zh-hans/5.1/ref/django-admin/#cmdoption-test-parallel) 选项，可以并行运行项目的测试，使用多个进程。

每个进程都会得到它们自己的数据库。你必须确保不同的测试用例不会访问相同的资源。例如，接触文件系统的测试用例应该创建一个临时目录供自己使用。

对于 Django 自身的测试套件，默认情况下启用了此选项。

- 只要操作系统支持（除了 Windows），此选项就会默认启用。
- 只要数据库后端支持（除了 Oracle），此选项就会默认启用。

### 次要特性

#### [`django.contrib.admin`](/zh-hans/5.1/ref/contrib/admin/#module-django.contrib.admin)

- 管理员视图现在具有 `model_admin` 或 `admin_site` 属性。
- 管理员更改视图的 URL 已更改（默认情况下是 `/admin/<app>/<model>/<pk>/`，现在是 `/admin/<app>/<model>/<pk>/change/`）。这不会影响您的应用程序，除非您已经硬编码了管理员的 URL。在这种情况下，建议使用 [反向管理员 URL](/zh-hans/5.1/ref/contrib/admin/#admin-reverse-urls) 来替代这些链接。请注意，旧的 URL 仍然会重定向到新的 URL 以保持向后兼容，但它可能在将来的版本中被删除。
- 添加了 [`ModelAdmin.get_list_select_related()`](/zh-hans/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_list_select_related) 方法，允许根据请求更改管理员的变更列表查询中使用的 `select_related()` 值。
- 已将 `available_apps` 上下文变量添加到 [`AdminSite.each_context()`](/zh-hans/5.1/ref/contrib/admin/#django.contrib.admin.AdminSite.each_context) 方法中，该变量列出了当前用户可用的应用程序。
- 添加了 [`AdminSite.empty_value_display`](/zh-hans/5.1/ref/contrib/admin/#django.contrib.admin.AdminSite.empty_value_display) 和 [`ModelAdmin.empty_value_display`](/zh-hans/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.empty_value_display)，用于覆盖管理员更改列表中空值的显示。您还可以为每个字段自定义该值。
- 在更改表单页面上添加了 jQuery 事件，用于 [在添加或删除内联表单时](/zh-hans/5.1/ref/contrib/admin/javascript/#admin-javascript-inline-form-events)。
- 时间选择器小部件包括一个“下午 6 点”的选项，以保持每 6 小时预定义选项的一致性。
- 现在，JavaScript 的 slug 生成支持罗马尼亚字符。

#### [`django.contrib.admindocs`](/zh-hans/5.1/ref/contrib/admin/admindocs/#module-django.contrib.admindocs)

- `admindocs` 的模型部分现在还描述了接受参数的方法，而不是忽略它们。

#### [`django.contrib.auth`](/zh-hans/5.1/topics/auth/#module-django.contrib.auth)

- PBKDF2 密码哈希器的默认迭代次数增加了 20%。这个向后兼容的更改不会影响那些已经子类化了 `django.contrib.auth.hashers.PBKDF2PasswordHasher` 来更改默认值的用户。
- 如果更改了 `BCryptSHA256PasswordHasher` 的 `rounds` 属性，它将更新密码。
- `AbstractBaseUser` 和 `BaseUserManager` 被移动到了新的 `django.contrib.auth.base_user` 模块，因此可以在不包括 `django.contrib.auth` 在 [`INSTALLED_APPS`](/zh-hans/5.1/ref/settings/#std-setting-INSTALLED_APPS) 中的情况下导入它们（在较旧的版本中，这样做会引发废弃警告，在 Django 1.9 中不再支持）。
- [`permission_required()`](/zh-hans/5.1/topics/auth/default/#django.contrib.auth.decorators.permission_required) 的权限参数接受所有类型的可迭代对象，而不仅仅是列表和元组。
- 新的 [`PersistentRemoteUserMiddleware`](/zh-hans/5.1/ref/middleware/#django.contrib.auth.middleware.PersistentRemoteUserMiddleware) 使得在仅在登录页面上填充标头的设置中使用 `REMOTE_USER` 成为可能，而不是在会话的每个请求中都填充。
- `django.contrib.auth.views.password_reset()` 视图接受一个 `extra_email_context` 参数。

#### [`django.contrib.contenttypes`](/zh-hans/5.1/ref/contrib/contenttypes/#module-django.contrib.contenttypes)

- 现在可以在 `GenericForeignKey` 中使用 [`order_with_respect_to`](/zh-hans/5.1/ref/models/options/#django.db.models.Options.order_with_respect_to)。

#### [`django.contrib.gis`](/zh-hans/5.1/ref/contrib/gis/#module-django.contrib.gis)

- 所有 `GeoQuerySet` 方法都已被废弃，并被 [等效的数据库函数](/zh-hans/5.1/ref/contrib/gis/functions/) 替代。一旦在您的代码中替换了这些旧方法，您甚至可以从启用 GIS 的类中删除特殊的 `GeoManager`。
- GDAL 接口现在支持从原始数据实例化基于文件和内存的 [GDALRaster 对象](/zh-hans/5.1/ref/contrib/gis/gdal/#raster-data-source-objects)。已添加了用于栅格属性（如投影或像素值）的设置器。
- 对于 PostGIS 用户，新的 [`RasterField`](/zh-hans/5.1/ref/contrib/gis/model-api/#django.contrib.gis.db.models.RasterField) 允许 [存储 GDALRaster 对象](/zh-hans/5.1/ref/contrib/gis/db-api/#creating-and-saving-raster-models)。它支持在保存模型时自动创建空间索引和重投影。但它目前还不支持空间查询。
- 新的 [`GDALRaster.warp()`](/zh-hans/5.1/ref/contrib/gis/gdal/#django.contrib.gis.gdal.GDALRaster.warp) 方法允许通过指定目标栅格属性（如原点、宽度、高度或像素大小等）来进行栅格重投影。
- 新的 [`GDALRaster.transform()`](/zh-hans/5.1/ref/contrib/gis/gdal/#django.contrib.gis.gdal.GDALRaster.transform) 方法允许通过指定目标 `srid` 来将栅格转换为不同的空间参考系统。
- 新的 [`GeoIP2`](/zh-hans/5.1/ref/contrib/gis/geoip2/#django.contrib.gis.geoip2.GeoIP2) 类允许使用 MaxMind 的 GeoLite2 数据库，其中包括对 IPv6 地址的支持。
- 包含在小部件中的默认 OpenLayers 库版本已从 2.13 更新为 2.13.1 。

#### [`django.contrib.postgres`](/zh-hans/5.1/ref/contrib/postgres/#module-django.contrib.postgres)

- 为一些内置字段添加了对 [`rangefield.contained_by`](/zh-hans/5.1/ref/contrib/postgres/fields/#std-fieldlookup-rangefield.contained_by) 查找的支持，这些字段对应于范围字段。
- 添加了 `django.contrib.postgres.fields.JSONField`。
- 添加了 [PostgreSQL 特有聚合函数](/zh-hans/5.1/ref/contrib/postgres/aggregates/)。
- 添加了 [`TransactionNow`](/zh-hans/5.1/ref/contrib/postgres/functions/#django.contrib.postgres.functions.TransactionNow) 数据库函数。

#### [`django.contrib.sessions`](/zh-hans/5.1/topics/http/sessions/#module-django.contrib.sessions)

- 会话模型和用于 `db` 和 `cached_db` 后端的 `SessionStore` 类已进行了重构，以允许自定义数据库会话后端基于它们构建。有关更多详细信息，请参阅 [扩展数据库后端的会话引擎](/zh-hans/5.1/topics/http/sessions/#extending-database-backed-session-engines)。

#### [`django.contrib.sites`](/zh-hans/5.1/ref/contrib/sites/#module-django.contrib.sites)

- [`get_current_site()`](/zh-hans/5.1/ref/contrib/sites/#django.contrib.sites.shortcuts.get_current_site) 现在处理了 `request.get_host()` 返回 `domain:port` 的情况，例如 `example.com:80`。如果查找失败，因为主机在数据库中找不到记录并且主机有一个端口，端口会被剥离，然后使用仅包含域名的部分重试查找。

#### [`django.contrib.syndication`](/zh-hans/5.1/ref/contrib/syndication/#module-django.contrib.syndication)

- 添加了对每个订阅项多个附件的支持。如果在 RSS 订阅中定义了多个附件，则会引发异常，因为 RSS 订阅不支持每个订阅项多个附件，而 Atom 订阅支持。

#### 缓存

- `django.core.cache.backends.base.BaseCache` 现在具有一个 `get_or_set()` 方法。
- [`django.views.decorators.cache.never_cache()`](/zh-hans/5.1/topics/http/decorators/#django.views.decorators.cache.never_cache) 现在发送更具说服力的头部信息（在 `Cache-Control` 中添加了 `no-cache, no-store, must-revalidate`），以更好地防止缓存。这也在 Django 1.8.8 中添加了。

#### CSRF

- 用于 CSRF 认证的请求头名称可以通过 [`CSRF_HEADER_NAME`](/zh-hans/5.1/ref/settings/#std-setting-CSRF_HEADER_NAME) 进行自定义。
- 如果设置了 [`CSRF_COOKIE_DOMAIN`](/zh-hans/5.1/ref/settings/#std-setting-CSRF_COOKIE_DOMAIN) 设置，CSRF 的 referer 头现在将与其进行验证。有关详细信息，请参阅 [工作方式](/zh-hans/5.1/ref/csrf/#how-csrf-works)。
- 新的 [`CSRF_TRUSTED_ORIGINS`](/zh-hans/5.1/ref/settings/#std-setting-CSRF_TRUSTED_ORIGINS) 设置提供了一种允许跨源不安全请求（例如 `POST`）通过 HTTPS 的方式。

#### 数据库后端

- PostgreSQL 后端（`django.db.backends.postgresql_psycopg2`）也可以使用 `django.db.backends.postgresql`。旧名称将继续保持以确保向后兼容。

#### 文件存储

- 当 [`upload_to`](/zh-hans/5.1/ref/models/fields/#django.db.models.FileField.upload_to) 是可调用对象时，现在会调用 [`Storage.get_valid_name()`](/zh-hans/5.1/ref/files/storage/#django.core.files.storage.Storage.get_valid_name)。
- 在使用 Python 3 时，[`File`](/zh-hans/5.1/ref/files/file/#django.core.files.File) 现在具有 `seekable()` 方法。

#### 表单

- [`ModelForm`](/zh-hans/5.1/topics/forms/modelforms/#django.forms.ModelForm) 接受新的 `Meta` 选项 `field_classes` 以自定义字段的类型。有关详细信息，请参阅 [覆盖默认字段](/zh-hans/5.1/topics/forms/modelforms/#modelforms-overriding-default-fields)。
- 现在可以使用 [`field_order`](/zh-hans/5.1/ref/forms/api/#django.forms.Form.field_order) 属性、`field_order` 构造函数参数或 [`order_fields()`](/zh-hans/5.1/ref/forms/api/#django.forms.Form.order_fields) 方法指定表单字段呈现的顺序。
- 现在可以在表单类内部指定表单前缀，而不仅仅是在实例化表单时。有关详细信息，请参阅 [表单前缀](/zh-hans/5.1/ref/forms/api/#form-prefix)。
- 现在可以 [指定要传递给表单集合中表单构造函数的关键字参数](/zh-hans/5.1/topics/forms/formsets/#custom-formset-form-kwargs)。
- [`SlugField`](/zh-hans/5.1/ref/forms/fields/#django.forms.SlugField) 现在接受一个 [`allow_unicode`](/zh-hans/5.1/ref/forms/fields/#django.forms.SlugField.allow_unicode) 参数，以允许在 slug 中使用 Unicode 字符。
- [`CharField`](/zh-hans/5.1/ref/forms/fields/#django.forms.CharField) 现在接受一个 [`strip`](/zh-hans/5.1/ref/forms/fields/#django.forms.CharField.strip) 参数，以去除输入数据的前导和尾随空格。由于默认为 `True`，这与之前的版本不同。
- 现在，表单字段支持 [`disabled`](/zh-hans/5.1/ref/forms/fields/#django.forms.Field.disabled) 参数，允许浏览器将字段小部件显示为禁用状态。
- 现在可以通过重写字段的 [`get_bound_field()`](/zh-hans/5.1/ref/forms/api/#django.forms.Field.get_bound_field) 方法来自定义绑定字段。

#### 通用视图

- 使用 `as_view()` 生成的基于类的视图现在具有 `view_class` 和 `view_initkwargs` 属性。
- 现在可以使用 [`method_decorator()`](/zh-hans/5.1/ref/utils/#django.utils.decorators.method_decorator) 与装饰器的列表或元组一起使用。它还可以用于 [装饰类而不是方法](/zh-hans/5.1/topics/class-based-views/intro/#id1)。

#### 国际化

- 当可用时，[`django.views.i18n.set_language()`](/zh-hans/5.1/topics/i18n/translation/#django.views.i18n.set_language) 视图现在正确重定向到 [已翻译的 URL](/zh-hans/5.1/topics/i18n/translation/#url-internationalization)。
- 如果在同一页上多次使用不同配置调用 `django.views.i18n.javascript_catalog()` 视图，它现在会正常工作。
- [`django.utils.timezone.make_aware()`](/zh-hans/5.1/ref/utils/#django.utils.timezone.make_aware) 函数新增了一个 `is_dst` 参数，以帮助解决夏令时转换期间的模糊时间。
- 现在可以使用 gettext 支持的语言区域变体。这通常用于可以使用不同字符集书写的语言，例如拉丁文和西里尔文（例如 `be@latin`）。
- 新增了 `django.views.i18n.json_catalog()` 视图，以帮助构建基于 Django 翻译的自定义客户端端国际化库。它返回一个包含翻译目录、格式设置和复数规则的 JSON 对象。
- 新增了 [`get_language_info`](/zh-hans/5.1/topics/i18n/translation/#std-templatetag-get_language_info) 模板标签返回的对象的 `name_translated` 属性。还新增了相应的模板过滤器：[`language_name_translated`](/zh-hans/5.1/topics/i18n/translation/#std-templatefilter-language_name_translated)。
- 现在你可以从项目的根目录运行 [`compilemessages`](/zh-hans/5.1/ref/django-admin/#django-admin-compilemessages)，它将找到所有由 [`makemessages`](/zh-hans/5.1/ref/django-admin/#django-admin-makemessages) 创建的应用程序消息文件。
- 现在 [`makemessages`](/zh-hans/5.1/ref/django-admin/#django-admin-makemessages) 每个区域目录调用一次 `xgettext` 而不是每个可翻译文件调用一次。这加快了本地化构建的速度。
- [`blocktrans`](/zh-hans/5.1/topics/i18n/translation/#std-templatetag-blocktrans) 支持使用 `asvar` 将其输出分配给变量。
- 新增了两种新语言：哥伦比亚西班牙语和苏格兰盖尔语。

#### 管理命令

- 新的 [`sendtestemail`](/zh-hans/5.1/ref/django-admin/#django-admin-sendtestemail) 命令允许您发送测试邮件，以轻松确认通过 Django 发送邮件是否正常工作。
- 为了增加 [`sqlmigrate`](/zh-hans/5.1/ref/django-admin/#django-admin-sqlmigrate) 生成的 SQL 代码的可读性，为每个迁移操作生成的 SQL 代码前面都有操作的描述。
- [`dumpdata`](/zh-hans/5.1/ref/django-admin/#django-admin-dumpdata) 命令的输出现在具有确定性的顺序。此外，当指定了 `--output` 选项时，它还在终端中显示一个进度条。
- [`createcachetable`](/zh-hans/5.1/ref/django-admin/#django-admin-createcachetable) 命令现在有一个 `--dry-run` 标志，可以打印出 SQL 而不执行它。
- [`startapp`](/zh-hans/5.1/ref/django-admin/#django-admin-startapp) 命令会创建一个 `apps.py` 文件。由于它不使用 `default_app_config` （ [一个不推荐使用的 API](/zh-hans/5.1/ref/applications/#configuring-applications-ref) ），你必须在 [`INSTALLED_APPS`](/zh-hans/5.1/ref/settings/#std-setting-INSTALLED_APPS) 中指定 app 配置的路径，例如 `'polls.apps.PollsConfig'`，以便使用它（而不仅仅是 `'polls'`）。
- 在使用 PostgreSQL 后端时，[`dbshell`](/zh-hans/5.1/ref/django-admin/#django-admin-dbshell) 命令可以使用设置文件中的密码来连接数据库（而不需要手动输入密码）。
- `django` 包可以作为脚本运行，即 `python -m django`，它的行为与 `django-admin` 相同。
- 具有 `--noinput` 选项的管理命令现在还支持 `--no-input` 作为该选项的别名。

#### 迁移

- 初始迁移现在带有一个 [`initial = True`](/zh-hans/5.1/topics/migrations/#django.db.migrations.Migration.initial) 类属性，这允许 [`migrate --fake-initial`](/zh-hans/5.1/ref/django-admin/#cmdoption-migrate-fake-initial) 更容易检测到初始迁移。
- 增加了对 `functools.partial` 和 `LazyObject` 实例的序列化支持。
- 当在 [`MIGRATION_MODULES`](/zh-hans/5.1/ref/settings/#std-setting-MIGRATION_MODULES) 中提供 `None` 作为值时，Django 将考虑该应用程序为没有迁移的应用程序。
- 在应用迁移时，当以 verbosity 2 或更高级别运行 migrate 命令时，" Rendering model states " 步骤现在仅计算已应用的迁移的模型状态。正在应用的迁移的模型状态将按需生成，大大减少了所需的内存。

  然而，这个改进在取消应用迁移时不适用，因此仍然需要预先计算和存储中间迁移状态。

  这个改进还要求 Django 不再支持混合迁移计划。混合计划包含一系列迁移，其中一些正在应用，而其他一些正在取消应用。这从未得到官方支持，并且从未有过公共 API 来支持这种行为。
- [`squashmigrations`](/zh-hans/5.1/ref/django-admin/#django-admin-squashmigrations) 命令现在支持指定要压缩的迁移的起始迁移。

#### 模型

- [`QuerySet.bulk_create()`](/zh-hans/5.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) 现在可以在代理模型上使用。
- 数据库配置增加了一个 [`TIME_ZONE`](/zh-hans/5.1/ref/settings/#std-setting-DATABASE-TIME_ZONE) 选项，用于与在 [`USE_TZ`](/zh-hans/5.1/ref/settings/#std-setting-USE_TZ) 为 `True` 时不支持时区的数据库交互，这些数据库将日期时间存储在本地时间中。
- 新增了 [`RelatedManager.set()`](/zh-hans/5.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.set) 方法，用于与由 `ForeignKey`、`GenericForeignKey` 和 `ManyToManyField` 创建的相关管理器交互。
- [`add()`](/zh-hans/5.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.add) 方法在反向外键上现在有一个 `bulk` 参数，允许执行一个查询，而不管要添加的对象数量如何，而不是每个对象执行一个查询。
- 在 [`Model.delete()`](/zh-hans/5.1/ref/models/instances/#django.db.models.Model.delete) 方法中添加了 `keep_parents` 参数，允许仅删除使用多表继承的模型中子模型的数据。
- [`Model.delete()`](/zh-hans/5.1/ref/models/instances/#django.db.models.Model.delete) 和 [`QuerySet.delete()`](/zh-hans/5.1/ref/models/querysets/#django.db.models.query.QuerySet.delete) 返回被删除的对象数量。
- 添加了一个系统检查，防止在同一模型上同时定义 `Meta.ordering` 和 `order_with_respect_to`。
- [`日期和时间`](/zh-hans/5.1/ref/models/querysets/#std-fieldlookup-year) 查询可以与其他查询（如 [`exact`](/zh-hans/5.1/ref/models/querysets/#std-fieldlookup-exact), [`gt`](/zh-hans/5.1/ref/models/querysets/#std-fieldlookup-gt), [`lt`](/zh-hans/5.1/ref/models/querysets/#std-fieldlookup-lt) 等）链接使用。例如：`Entry.objects.filter(pub_date__month__gt=6)`。
- 时间查询（小时，分钟，秒）现在对所有数据库后端都受到 [`TimeField`](/zh-hans/5.1/ref/models/fields/#django.db.models.TimeField) 的支持。在 Django 1.7 中添加了对除 SQLite 外的后端的支持，但未记录在文档中。
- 你可以通过指定 [`Avg`](/zh-hans/5.1/ref/models/querysets/#django.db.models.Avg) 聚合的 `output_field` 参数来对非数字列（如 `DurationField`）进行聚合。
- 在 [`DateTimeField`](/zh-hans/5.1/ref/models/fields/#django.db.models.DateTimeField) 中添加了 [`date`](/zh-hans/5.1/ref/models/querysets/#std-fieldlookup-date) 查询，允许仅查询字段的日期部分。
- 添加了 [`Greatest`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Greatest) 和 [`Least`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Least) 数据库函数。
- 添加了 [`Now`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Now) 数据库函数，该函数返回当前的日期和时间。
- [`Transform`](/zh-hans/5.1/ref/models/lookups/#django.db.models.Transform) 现在是 [Func()](/zh-hans/5.1/ref/models/expressions/#func-expressions) 的子类，这使得 `Transform` 可以像常规的 `Func` 一样用在表达式的右侧。这允许注册一些数据库函数，如 [`Length`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Length)、[`Lower`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Lower) 和 [`Upper`](/zh-hans/5.1/ref/models/database-functions/#django.db.models.functions.Upper) 作为转换函数。
- [`SlugField`](/zh-hans/5.1/ref/models/fields/#django.db.models.SlugField) 现在接受一个 [`allow_unicode`](/zh-hans/5.1/ref/models/fields/#django.db.models.SlugField.allow_unicode) 参数，允许在 slug 中使用 Unicode 字符。
- 在 `QuerySet.distinct()` 中增加了对注解引用的支持。
- `connection.queries` 在 SQLite 上显示带有替代参数的查询。
- [查询表达式](/zh-hans/5.1/ref/models/expressions/) 现在可以在使用 `save()`, `create()` 和 `bulk_create()` 创建新模型实例时使用。

#### 请求和响应

- 除非显式设置 [`HttpResponse.reason_phrase`](/zh-hans/5.1/ref/request-response/#django.http.HttpResponse.reason_phrase)，否则它现在由 [`HttpResponse.status_code`](/zh-hans/5.1/ref/request-response/#django.http.HttpResponse.status_code) 的当前值确定。在构造函数之外修改 `status_code` 的值也会修改 `reason_phrase` 的值。
- 调试视图现在在 Python 3 上显示链式异常的详细信息。
- 默认的 40x 错误视图现在接受第二个位置参数，即触发视图的异常。
- 视图错误处理程序现在支持 [`TemplateResponse`](/zh-hans/5.1/ref/template-response/#django.template.response.TemplateResponse)，这在使用基于类的视图时常常使用。
- 由 `render()` 方法引发的异常现在会传递给每个中间件的 `process_exception()` 方法。
- 请求中间件现在可以将 [`HttpRequest.urlconf`](/zh-hans/5.1/ref/request-response/#django.http.HttpRequest.urlconf) 设置为 `None`，以撤销之前中间件所做的任何更改并返回使用 [`ROOT_URLCONF`](/zh-hans/5.1/ref/settings/#std-setting-ROOT_URLCONF)。
- 在 [`CommonMiddleware`](/zh-hans/5.1/ref/middleware/#django.middleware.common.CommonMiddleware) 中的 [`DISALLOWED_USER_AGENTS`](/zh-hans/5.1/ref/settings/#std-setting-DISALLOWED_USER_AGENTS) 检查现在引发 [`PermissionDenied`](/zh-hans/5.1/ref/exceptions/#django.core.exceptions.PermissionDenied) 异常，而不是返回 [`HttpResponseForbidden`](/zh-hans/5.1/ref/request-response/#django.http.HttpResponseForbidden)，以便调用 [`handler403`](/zh-hans/5.1/ref/urls/#django.conf.urls.handler403)。
- 添加了 [`HttpRequest.get_port()`](/zh-hans/5.1/ref/request-response/#django.http.HttpRequest.get_port) 方法，用于获取请求的起始端口。
- 在 [`JsonResponse`](/zh-hans/5.1/ref/request-response/#django.http.JsonResponse) 中添加了 `json_dumps_params` 参数，允许将关键字参数传递给用于生成响应的 `json.dumps()` 调用。
- [`BrokenLinkEmailsMiddleware`](/zh-hans/5.1/ref/middleware/#django.middleware.common.BrokenLinkEmailsMiddleware) 现在在引用者等于请求的 URL 时忽略 404 错误。为了规避已经实施的空引用检查，一些网络爬虫将引用者设置为请求的 URL。

#### 模板

- 使用 [`simple_tag()`](/zh-hans/5.1/howto/custom-template-tags/#django.template.Library.simple_tag) 辅助程序创建的模板标签现在可以使用 `as` 参数将结果存储在模板变量中。
- 添加了 [`Context.setdefault()`](/zh-hans/5.1/ref/templates/api/#django.template.Context.setdefault) 方法。
- 添加了 [django.template](/zh-hans/5.1/ref/logging/#django-template-logger) 记录器，并包括以下消息：

  - 对于缺少上下文变量的情况，添加了一个 `DEBUG` 级别的消息。
  - 在关闭调试模式时，对于在渲染 `{% include %}` 期间引发的未捕获异常，添加了一个 `WARNING` 级别的消息（这对于 `{% include %}` 会将异常消除并返回空字符串的情况很有帮助）。
- [`firstof`](/zh-hans/5.1/ref/templates/builtins/#std-templatetag-firstof) 模板标签支持使用 'as' 将输出存储在一个变量中。
- [`Context.update()`](/zh-hans/5.1/ref/templates/api/#django.template.Context.update) can now be used as
  a context manager.
- Django 模板加载器现在可以递归地扩展模板。
- 调试页面模板的事后分析现在包括安装的每个引擎的输出。
- 为自定义模板引擎添加了 [调试页面集成](/zh-hans/5.1/howto/custom-template-backend/#template-debug-integration)。
- [`DjangoTemplates`](/zh-hans/5.1/topics/templates/#django.template.backends.django.DjangoTemplates) 后端通过模板 [`OPTIONS`](/zh-hans/5.1/ref/settings/#std-setting-TEMPLATES-OPTIONS) 获得了明确注册库和内置函数的能力。
- `timesince` 和 `timeuntil` 过滤器在处理大时间跨度时进行了改进，以应对闰年。
- `include` 标签现在在模板渲染期间缓存解析的模板对象，加快了在诸如 for 循环等地方的重复使用。

#### 测试

- 在测试客户端响应中添加了 [`json()`](/zh-hans/5.1/topics/testing/tools/#django.test.Response.json) 方法，以便访问响应体作为 JSON。
- 在测试客户端中添加了 [`force_login()`](/zh-hans/5.1/topics/testing/tools/#django.test.Client.force_login) 方法。使用该方法模拟用户登录站点的效果，同时跳过 [`login()`](/zh-hans/5.1/topics/testing/tools/#django.test.Client.login) 的身份验证和验证步骤。

#### URLs

- URL 模式中现在允许使用正则表达式的环视断言。
- 应用程序命名空间现在可以通过在包含的模块或对象上设置 `app_name` 属性来设置。也可以通过将一个 2 元组（\<模式列表\>，\<应用程序命名空间\>）作为 `include()` 的第一个参数来设置。
- 已添加了用于检测常见 URL 模式错误的系统检查。

#### 验证器

- 添加了 [`django.core.validators.int_list_validator()`](/zh-hans/5.1/ref/validators/#django.core.validators.int_list_validator)，用于生成验证包含整数并用自定义字符分隔的字符串的验证器。
- [`EmailValidator`](/zh-hans/5.1/ref/validators/#django.core.validators.EmailValidator) 现在根据 [**RFC 1034**](https://datatracker.ietf.org/doc/html/rfc1034.html)，限制了域名标签的长度为 63 个字符。
- 添加了 [`validate_unicode_slug()`](/zh-hans/5.1/ref/validators/#django.core.validators.validate_unicode_slug)，用于验证可能包含 Unicode 字符的 slugs。

## 1.9 版本中的不向后兼容变更

> **Warning**
>
> 除了本节中概述的更改之外，请确保查看 [在 1.9 版本中移除的功能。](#removed-features-1-9)，了解已经完成弃用周期并因此被移除的功能。如果您没有在给定功能的弃用时间内更新您的代码，其移除可能会被视为不兼容的更改。

### 数据库后端 API

- 一些新的测试依赖于后端能够自省列的默认值（将结果返回为 `Field.default`）。如果您的后端没有实现这个功能，您可以将数据库特性 `can_introspect_default` 设置为 `False`。您可能希望参考 Django 包含的后端的实现来进行审查（[#24245](https://code.djangoproject.com/ticket/24245)）。
- 不鼓励在 DB-API 模块级别注册全局适配器或转换器来处理作为查询参数传递或作为查询结果返回的不支持时区的 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 值的时区信息。这可能会与其他库发生冲突。

  向从数据库获取的 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 值添加时区的推荐方法是在 `DatabaseOperations.get_db_converters()` 中为 `DateTimeField` 注册一个转换器。

  已移除了 `needs_datetime_string_cast` 数据库特性。设置了这个特性的数据库后端必须按照上述说明注册一个转换器。
- `DatabaseOperations.value_to_db_<type>()` 方法被重命名为 `adapt_<type>field_value()`，以与 `convert_<type>field_value()` 方法保持一致。
- 要使用新的 `date` 查询，第三方数据库后端可能需要实现 `DatabaseOperations.datetime_cast_date_sql()` 方法。
- 添加了 `DatabaseOperations.time_extract_sql()` 方法。它调用现有的 `date_extract_sql()` 方法。SQLite 后端会重写此方法，以向 [`TimeField`](/zh-hans/5.1/ref/models/fields/#django.db.models.TimeField) 添加时间查询（小时、分钟、秒），第三方数据库后端可能需要实现此方法。
- 已删除 `DatabaseOperations.datetime_cast_sql()` 方法（请不要与上面提到的 `DatabaseOperations.datetime_cast_date_sql()` 混淆）。这个方法在很多年前用于在 Oracle 上格式化日期，但很多年来没有被任何核心后端重写，也没有在 Django 代码或测试中被调用过。
- 为了支持测试并行化，您必须实现 `DatabaseCreation._clone_test_db()` 方法并设置 `DatabaseFeatures.can_clone_databases = True`。您可能需要调整 `DatabaseCreation.get_test_db_clone_settings()`。

### 原来的默认设置是元组，现在改为列表

在 `django.conf.global_settings` 中的默认设置原来是列表和元组的组合。以前是元组的所有设置现在都改为了列表。

### 模板加载器上的 `is_usable` 属性已被移除。

以前，Django 模板加载器需要定义一个 `is_usable` 属性。如果在模板设置中配置了一个加载器并且该属性为 `False`，则加载器将被静默忽略。在实际应用中，这只有 egg 加载器用于检测是否安装了 `setuptools`。现在已删除 `is_usable` 属性，而 egg 加载器在运行时如果没有安装 `setuptools` 则会失败。

### 相关集合直接赋值

在 ORM 中直接分配相关对象以前会执行 `clear()`，然后调用 `add()`。这导致了不必要的大量数据更改，并且阻止使用 [`m2m_changed`](/zh-hans/5.1/ref/signals/#django.db.models.signals.m2m_changed) 信号来跟踪多对多关系中的个别更改。

直接赋值现在依赖于相关管理器上的新 [`set()`](/zh-hans/5.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.set) 方法，默认情况下只处理现有相关集合与新分配的相关集合之间的更改。可以通过将直接赋值替换为带有关键字参数 `clear=True` 的 `set()` 调用来恢复先前的行为。

`ModelForm`，因此 `ModelAdmin`，在内部对于多对多关系依赖于直接赋值，并因此现在使用新行为。

### 基于文件系统的模板加载器捕获更具体的异常

使用 [`filesystem.Loader`](/zh-hans/5.1/ref/templates/api/#django.template.loaders.filesystem.Loader) 或 [`app_directories.Loader`](/zh-hans/5.1/ref/templates/api/#django.template.loaders.app_directories.Loader) 模板加载器时，较早版本的 Django 如果模板源存在但不可读，会引发 [`TemplateDoesNotExist`](/zh-hans/5.1/topics/templates/#django.template.TemplateDoesNotExist) 错误。这可能发生在许多情况下，例如如果 Django 没有权限打开文件，或者模板源是一个目录。现在，只有当模板源不存在时，Django 才会抑制异常。所有其他情况都会引发原始的 `IOError`。

### HTTP 重定向不再强制要求使用绝对 URI

相对重定向不再被转换为绝对 URI。[**RFC 2616**](https://datatracker.ietf.org/doc/html/rfc2616.html) 要求重定向响应中的 `Location` 标头必须是绝对 URI，但它已被 [**RFC 7231**](https://datatracker.ietf.org/doc/html/rfc7231.html) 取代，允许在 `Location` 中使用相对 URI，承认用户代理的实际实践，几乎所有用户代理都支持相对 URI。

因此，传递给 `assertRedirects` 的预期 URL 通常不再应包括 URL 的方案和域部分。例如，`self.assertRedirects(response, 'http://testserver/some-url/')` 应该替换为 `self.assertRedirects(response, '/some-url/')` （除非重定向明确包含绝对 URL）。

在极少数情况下，如果您需要旧的行为（使用一个古老版本的 Apache 和 `mod_scgi` 发现将相对重定向解释为 "内部重定向" 的情况），您可以通过编写自定义中间件来恢复它：

```
class LocationHeaderFix(object):
    def process_response(self, request, response):
        if "Location" in response:
            response["Location"] = request.build_absolute_uri(response["Location"])
        return response
```

### 不再支持 PostgreSQL 9.0 版本

PostgreSQL 9.0 的上游支持于 2015 年 9 月结束。因此，Django 1.9 将 9.1 版本设定为其正式支持的最低 PostgreSQL 版本。

### 不再支持 Oracle 11.1 版本

Oracle 11.1 的上游支持于 2015 年 8 月结束。因此，Django 1.9 将 11.2 版本设定为其正式支持的最低 Oracle 版本。

### 关于相关管理器的 `add()` 方法的批量行为

为了提高性能，由 `ForeignKey` 和 `GenericForeignKey` 创建的相关管理器的 `add()` 方法从一系列 `Model.save()` 调用改为单个 `QuerySet.update()` 调用。这个变化意味着不再发送 `pre_save` 和 `post_save` 信号。您可以使用 `bulk=False` 关键字参数来恢复到以前的行为。

### 模板中移除了 `LoaderOrigin` 和 `StringOrigin`

在之前的 Django 版本中，当一个模板引擎以 `True` 的调试设置初始化时，一个 `django.template.loader.LoaderOrigin` 或 `django.template.base.StringOrigin` 的实例被设置为模板对象的 origin 属性。这些类已经合并为 [`Origin`](/zh-hans/5.1/ref/templates/api/#django.template.base.Origin)，并且无论引擎的调试设置如何，都会始终设置。为了最小程度的向后兼容性，旧的类名将保留为新的 `Origin` 类的别名，直到 Django 2.0。

### 默认日志配置的更改

为了更容易编写自定义的日志配置，Django 的默认日志配置不再定义 `django.request` 和 `django.security` 记录器。取而代之的是，它定义了一个名为 `django` 的记录器，过滤级别为 `INFO`，具有两个处理程序：

- `console`：过滤级别为 `INFO`，仅在 `DEBUG=True` 时激活。
- `mail_admins`：过滤级别为 `ERROR`，仅在 `DEBUG=False` 时激活。

如果您没有覆盖 Django 的默认日志配置，您的行为应该只会发生较少的变化，但您可能会在 `runserver` 控制台上看到一些新的日志记录，例如。

如果您正在覆盖 Django 的默认日志配置，您应该检查您的配置与新默认值如何合并。

### 在错误报告中的 `HttpRequest` 详细信息

每次在调试页面的 HTML 版本和错误邮件中作为堆栈帧变量出现时都显示完整的 [`HttpRequest`](/zh-hans/5.1/ref/request-response/#django.http.HttpRequest) 详细信息是多余的。因此，HTTP 请求现在将显示与其他变量相同的标准表示形式（`repr(request)`）。因此，删除了 `ExceptionReporterFilter.get_request_repr()` 方法和未记录的 `django.http.build_request_repr()` 函数。

电子邮件的文本版本内容已修改，以提供与 AJAX 请求的情况相同结构的回溯。回溯详细信息由 `ExceptionReporter.get_traceback_text()` 方法呈现。

### 移除了日期时间的时区感知全局适配器和转换器

Django 不再注册全局适配器和转换器来管理发送到数据库的查询参数中的 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 值的时区信息，以及从查询结果中读取的时区信息。这个变化影响满足以下所有条件的项目：

- [`USE_TZ`](/zh-hans/5.1/ref/settings/#std-setting-USE_TZ) 设置为 `True`。
- 数据库是 SQLite、MySQL、Oracle 或不支持时区的第三方数据库。如有疑问，您可以检查 `connection.features.supports_timezones` 的值。
- 代码在 ORM 之外查询数据库，通常使用 `cursor.execute(sql, params)`。

如果您将感知的 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 参数传递给这些查询，您应该将它们转换为 UTC 中的非感知日期时间：

```
from django.utils import timezone

param = timezone.make_naive(param, timezone.utc)
```

如果您未这样做，转换将按照早期版本（带有弃用警告）中的方式执行，直到 Django 1.11 为止。 Django 2.0 不会执行任何转换，这可能导致数据损坏。

如果您从结果中读取 [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 值，它们将是非感知的，而不是感知的。您可以按以下方式进行补偿：

```
from django.utils import timezone

value = timezone.make_aware(value, timezone.utc)
```

如果您通过 ORM 查询数据库，即使使用 [`raw()`](/zh-hans/5.1/ref/models/querysets/#django.db.models.query.QuerySet.raw) 查询，也不需要进行上述操作。ORM 会处理时区信息的管理。

### 在配置模板时导入模板标签模块

[`DjangoTemplates`](/zh-hans/5.1/topics/templates/#django.template.backends.django.DjangoTemplates) 后端现在在实例化时执行已安装的模板标签模块的发现。此更新使得在定义 [`DjangoTemplates`](/zh-hans/5.1/topics/templates/#django.template.backends.django.DjangoTemplates) 后端时，可以通过 [`OPTIONS`](/zh-hans/5.1/ref/settings/#std-setting-TEMPLATES-OPTIONS) 的 `'libraries'` 键明确提供库。模板标签模块中的导入或语法错误现在会在实例化时提前失败，而不是在首次编译带有 [`{% load %}`](/zh-hans/5.1/ref/templates/builtins/#std-templatetag-load) 标签的模板时失败。

### 已删除 `django.template.base.add_to_builtins()`。

虽然它是一个私有 API，但项目通常使用 `add_to_builtins()` 来使模板标签和过滤器在不使用 [`{% load %}`](/zh-hans/5.1/ref/templates/builtins/#std-templatetag-load) 标签的情况下可用。这个 API 已经正式化。现在项目应该在定义 [`DjangoTemplates`](/zh-hans/5.1/topics/templates/#django.template.backends.django.DjangoTemplates) 后端时，通过 [`OPTIONS`](/zh-hans/5.1/ref/settings/#std-setting-TEMPLATES-OPTIONS) 的 `'builtins'` 键来定义内置库。

### `simple_tag` 现在在标签输出中包装了 `conditional_escape`

通常，模板标签不会自动转义其内容，这种行为是被 [文档记录的](/zh-hans/5.1/howto/custom-template-tags/#tags-auto-escaping)。对于像 [`inclusion_tag`](/zh-hans/5.1/howto/custom-template-tags/#django.template.Library.inclusion_tag) 这样的标签，这不是问题，因为被包含的模板会执行自动转义。对于 `assignment_tag()`，当它在模板中作为变量使用时，输出会被转义。

然而，对于 [`simple_tag`](/zh-hans/5.1/howto/custom-template-tags/#django.template.Library.simple_tag) 的预期用例，很容易出现不正确的 HTML 和可能的 XSS 攻击。例如：

```
@register.simple_tag(takes_context=True)
def greeting(context):
    return "Hello {0}!".format(context["request"].user.first_name)
```

在较早版本的 Django 中，这将是一个 XSS 问题，因为\`\`user.first\_name\`\` 没有经过转义。

在 Django 1.9 中，这个问题得到了修复：如果模板上下文设置了 `autoescape=True` （默认值），那么 `simple_tag` 将使用 [`conditional_escape()`](/zh-hans/5.1/ref/utils/#django.utils.html.conditional_escape) 包装标签函数的输出。

要修复您的 `simple_tag`，最好遵循以下实践：

- 生成 HTML 的任何代码都应该使用模板系统或 [`format_html()`](/zh-hans/5.1/ref/utils/#django.utils.html.format_html)。
- 如果 `simple_tag` 的输出需要转义，请使用 [`escape()`](/zh-hans/5.1/ref/utils/#django.utils.html.escape) 或 [`conditional_escape()`](/zh-hans/5.1/ref/utils/#django.utils.html.conditional_escape)。
- 如果您绝对确定您正在输出来自可信源的 HTML（例如，由管理员输入的 HTML 存储在 CMS 字段中），您可以使用 [`mark_safe()`](/zh-hans/5.1/ref/utils/#django.utils.safestring.mark_safe) 来标记它。

遵循这些规则的标签无论在 Django 1.9+ 还是之前的版本上运行，都将是正确和安全的。

### `Paginator.page_range`

[`Paginator.page_range`](/zh-hans/5.1/ref/paginator/#django.core.paginator.Paginator.page_range) 现在是一个迭代器而不是一个列表。

在 Django 1.8 之前的版本中，`Paginator.page_range` 在 Python 2 中返回一个 `list`，在 Python 3 中返回一个 `range`。Django 1.8 一致返回一个列表，但迭代器更有效率。

依赖于 `list` 特定功能（如索引）的现有代码可以通过使用 `list()` 将迭代器转换为 `list` 来迁移。

### 隐式的 `QuerySet` `__in` 查询已移除

在早期版本中，类似以下的查询：

```
Model.objects.filter(related_id=RelatedModel.objects.all())
```

会隐式转换为：

```
Model.objects.filter(related_id__in=RelatedModel.objects.all())
```

这将导致 SQL 查询类似于 `"related_id IN (SELECT id FROM ...)"`。

这种隐式的 `__in` 不再发生，因此 "IN" SQL 现在变成了 "=", 如果子查询返回多个结果，至少某些数据库会抛出错误。

### `contrib.admin` 浏览器支持

管理员不再支持 Internet Explorer 8 及以下版本，因为这些浏览器已经到达生命周期终点。

已删除支持 Internet Explorer 6 和 7 的 CSS 和图像。 PNG 和 GIF 图标已被替换为 SVG 图标，这些图标不受 Internet Explorer 8 及更早版本的支持。

嵌入在管理员中的 jQuery 库已从 1.11.2 版本升级到 2.1.4 版本。 jQuery 2.x 具有与 jQuery 1.x 相同的 API，但不支持 Internet Explorer 6 、 7 或 8，从而实现更好的性能和更小的文件大小。如果您需要支持 IE8 并且必须使用最新版本的 Django，您可以通过创建具有以下结构的 Django 应用程序来覆盖管理员的 jQuery 副本：

```text
app/static/admin/js/vendor/
    jquery.js
    jquery.min.js
```

### 在 `setuptools` 5.5.x 安装 Django 时出现 `SyntaxError` 错误

当使用 `setuptools` 5.5.x 安装 Django 1.9 或 1.9.1 时，你会看到：

```shell
Compiling django/conf/app_template/apps.py ...
  File "django/conf/app_template/apps.py", line 4
    class {{ camel_case_app_name }}Config(AppConfig):
          ^
SyntaxError: invalid syntax

Compiling django/conf/app_template/models.py ...
  File "django/conf/app_template/models.py", line 1
    {{ unicode_literals }}from django.db import models
                             ^
SyntaxError: invalid syntax
```

你可以安全地忽略这些错误（Django 仍然会正常安装），但你可以通过升级 `setuptools` 到一个更近期的版本来避免它们。如果你使用 pip，你可以使用 `python -m pip install -U pip` 来升级 pip，这也会升级 `setuptools`。这个问题在后续版本的 Django 中已经得到解决，如 [Django 1.9.2 版本发行说明](/zh-hans/5.1/releases/1.9.2/) 中所描述的那样。

### 杂项

- `contrib.admin` 中的 jQuery 静态文件已经移动到一个名为 `vendor/jquery` 的子目录中。
- 在管理 changelist 的 `list_display` 单元格中，空列的显示文本已经从 `(None)` （或其翻译等效）更改为 `-` （破折号）。
- `django.http.responses.REASON_PHRASES` 和 `django.core.handlers.wsgi.STATUS_CODE_TEXT` 已被移除。请改为使用 Python 标准库：对于 Python 3，使用 [`http.client.responses`](https://docs.python.org/3/library/http.client.html#http.client.responses)，对于 Python 2，使用 [httplib.responses](https://docs.python.org/2/library/httplib.html#httplib.responses)。
- `ValuesQuerySet` 和 `ValuesListQuerySet` 已被移除。
- `admin/base.html` 模板不再设置 `window.__admin_media_prefix__` 或 `window.__admin_utc_offset__`。在 JavaScript 中使用该值构建绝对 URL 的图像引用已经移动到 CSS 中，以便更容易进行自定义。UTC 偏移量存储在 `<body>` 标签的数据属性中。
- `CommaSeparatedIntegerField` 的验证已经更加精细化，不再允许像 `','`、`',1'` 和 `'1,,2'` 这样的值。
- 表单的初始化已经从 [`ProcessFormView.get()`](/zh-hans/5.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.ProcessFormView.get) 方法移动到新的 [`FormMixin.get_context_data()`](/zh-hans/5.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin.get_context_data) 方法。如果你曾经重写了 `get_context_data()` 方法而没有调用 `super()`，这可能会造成不兼容。
- 不再支持 PostGIS 1.5 版本。
- `django.contrib.sites.models.Site.domain` 字段已更改为 [`unique`](/zh-hans/5.1/ref/models/fields/#django.db.models.Field.unique)。
- 为了强制执行测试隔离，现在默认情况下在 [`SimpleTestCase`](/zh-hans/5.1/topics/testing/tools/#django.test.SimpleTestCase) 测试中不允许数据库查询。你可以通过在测试类上设置 `allow_database_queries` 类属性为 `True` 来禁用这个行为。
- `ResolverMatch.app_name` 已更改，现在在嵌套命名空间的情况下包含完整的命名空间路径。为了与 `ResolverMatch.namespace` 保持一致，现在空值是一个空字符串而不是 `None`。
- 为了增强安全性，会话密钥必须至少为 8 个字符。
- 已移除私有函数 `django.utils.functional.total_ordering()`。它包含了对于早于 Python 2.7.3 版本中 `functools.total_ordering()` bug 的一个解决方法。
- XML 序列化（通过 [`dumpdata`](/zh-hans/5.1/ref/django-admin/#django-admin-dumpdata) 或 syndication 框架）曾经会输出它接收到的任何字符。现在，如果要序列化的内容包含 XML 1.0 标准不允许的控制字符，序列化将会失败并引发 [`ValueError`](https://docs.python.org/3/library/exceptions.html#ValueError)。
- 现在，默认情况下，[`CharField`](/zh-hans/5.1/ref/forms/fields/#django.forms.CharField) 会自动去除输入的前导和尾随空白。你可以通过将新的 [`strip`](/zh-hans/5.1/ref/forms/fields/#django.forms.CharField.strip) 参数设置为 `False` 来禁用这个功能。
- 在翻译并使用两个或更多连续百分号的模板文本，例如 `"%%"`，在运行 `makemessages` 后可能会有一个新的 `msgid` （很可能翻译会被标记为模糊）。新的 `msgid` 将被标记为 `"#, python-format"`。
- 如果既没有设置 [`request.current_app`](/zh-hans/5.1/ref/request-response/#django.http.HttpRequest.current_app)，也没有设置 [`Context.current_app`](/zh-hans/5.1/ref/templates/api/#django.template.Context)，那么 [`url`](/zh-hans/5.1/ref/templates/builtins/#std-templatetag-url) 模板标签现在将使用当前请求的命名空间。如果不想使用命名空间提示，请将 `request.current_app` 设置为 `None`。
- [`SILENCED_SYSTEM_CHECKS`](/zh-hans/5.1/ref/settings/#std-setting-SILENCED_SYSTEM_CHECKS) 设置现在会禁止所有级别的消息。以前，`ERROR` 级别或更高级别的消息会打印到控制台。
- `FlatPage.enable_comments` 字段已从 `FlatPageAdmin` 中移除，因为它未被应用程序使用。如果你的项目或第三方应用程序使用它，请 [创建一个自定义的 ModelAdmin](/zh-hans/5.1/ref/contrib/flatpages/#flatpages-admin) 来将其添加回去。
- [`setup_databases()`](/zh-hans/5.1/topics/testing/advanced/#django.test.runner.DiscoverRunner.setup_databases) 的返回值和 [`teardown_databases()`](/zh-hans/5.1/topics/testing/advanced/#django.test.runner.DiscoverRunner.teardown_databases) 的第一个参数已经改变。它们以前是 `(old_names, mirrors)` 元组，现在它们只是第一个项目，即 `old_names`。
- 默认情况下，[`LiveServerTestCase`](/zh-hans/5.1/topics/testing/tools/#django.test.LiveServerTestCase) 尝试在 8081-8179 范围内查找可用端口，而不仅仅是尝试端口 8081。
- 现在，对于 [`ModelAdmin`](/zh-hans/5.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin) 的系统检查会检查实例而不是类。
- 出于性能原因，已经移除了应用混合迁移计划的私有 API 。混合计划包括一系列迁移，其中一些正在应用，而其他一些正在取消应用。
- 位于 `django.db.models.fields.related` （私有 API）中的相关模型对象描述符类已经从 `related` 模块移动到 `related_descriptors`，并且被重命名如下：

  - `ReverseSingleRelatedObjectDescriptor` 是 `ForwardManyToOneDescriptor`
  - `SingleRelatedObjectDescriptor` 是 `ReverseOneToOneDescriptor`
  - `ForeignRelatedObjectsDescriptor` 是 `ReverseManyToOneDescriptor`
  - `ManyRelatedObjectsDescriptor` 是 `ManyToManyDescriptor`
- 如果你实现了自定义的 [`handler404`](/zh-hans/5.1/ref/urls/#django.conf.urls.handler404) 视图，它必须返回一个带有 HTTP 404 状态代码的响应。使用 [`HttpResponseNotFound`](/zh-hans/5.1/ref/request-response/#django.http.HttpResponseNotFound) 或将 `status=404` 传递给 [`HttpResponse`](/zh-hans/5.1/ref/request-response/#django.http.HttpResponse)。否则，在 `DEBUG=False` 的情况下，[`APPEND_SLASH`](/zh-hans/5.1/ref/settings/#std-setting-APPEND_SLASH) 不会正确工作。

## 在 1.9 中被废弃的功能

### `assignment_tag()`

Django 1.4 版本添加了 `assignment_tag` 辅助函数，以简化在模板变量中存储结果的模板标签的创建。[`simple_tag()`](/zh-hans/5.1/howto/custom-template-tags/#django.template.Library.simple_tag) 辅助函数也具备了相同的功能，因此使得 `assignment_tag` 已经过时。使用 `assignment_tag` 的标签应该更新为使用 `simple_tag`。

### `{% cycle %}` 语法可以接受逗号分隔的参数

[`cycle`](/zh-hans/5.1/ref/templates/builtins/#std-templatetag-cycle) 标签支持来自先前 Django 版本的旧语法：

```html+django
{% cycle row1,row2,row3 %}
```

使用旧语法会导致解析错误，因此在加速弃用后，将在 Django 1.10 中删除对旧语法的支持。

### `ForeignKey` 和 `OneToOneField` 的 `on_delete` 参数

为了增加对级联模型删除的认知，在 Django 2.0 中将要求在 `ForeignKey` 和 `OneToOneField` 中使用 `on_delete` 参数。

更新模型和现有的迁移以显式设置参数。由于默认值是 `models.CASCADE`，因此请在所有不使用不同选项的 `ForeignKey` 和 `OneToOneField` 上添加 `on_delete=models.CASCADE`。如果不关心与较早版本的 Django 的兼容性，也可以将其作为第二个位置参数传递。

### `Field.rel` 变更

`Field.rel` 及其方法和属性已更改以匹配相关字段的 API。`Field.rel` 属性被重命名为 `remote_field`，许多其方法和属性要么更改，要么重命名。

这些更改的目的是为关系字段提供一个有文档记录的 API 。

### `GeoManager` 和 `GeoQuerySet` 的自定义方法

所有自定义的 `GeoQuerySet` 方法（如 `area()`、`distance()`、`gml()` 等）都已被等效的地理表达式注释所取代（请参见新特性）。因此，现在已经不再需要为支持 GIS 的模型设置自定义的 `GeoManager`。一旦你的代码不再调用任何已弃用的方法，你可以简单地从模型中删除 `objects = GeoManager()` 行。

### 模板加载器的 API 已经改变。

Django 模板加载器已更新，允许递归模板扩展。这个变化需要一个新的模板加载器 API。旧的 `load_template()` 和 `load_template_sources()` 方法现在已被弃用。关于新 API 的详细信息可以在 [模板加载器文档中](/zh-hans/5.1/ref/templates/api/#custom-template-loaders) 找到。

### 将一个 3 元组或一个 `app_name` 传递给 `include()`

传递元组作为参数到 `include()` 的实例命名空间部分已被替换为通过 `include()` 传递 `namespace` 参数。例如：

```
polls_patterns = [
    url(...),
]

urlpatterns = [
    url(r"^polls/", include((polls_patterns, "polls", "author-polls"))),
]
```

变成：

```
polls_patterns = (
    [
        url(...),
    ],
    "polls",
)  # 'polls' is the app_name

urlpatterns = [
    url(r"^polls/", include(polls_patterns, namespace="author-polls")),
]
```

`include()` 中的 `app_name` 参数已被替换为传递一个 2 元组（如上所示），或者传递一个具有 `app_name` 属性的对象或模块（如下所示）。如果以这种新方式设置了 `app_name`，那么 `namespace` 参数将不再需要。它将默认为 `app_name` 的值。例如，教程中的 URL 模式已更改为：

*`mysite/urls.py`*

```python
urlpatterns = [url(r"^polls/", include("polls.urls", namespace="polls")), ...]
```

到：

*`mysite/urls.py`*

```python
urlpatterns = [
    url(r"^polls/", include("polls.urls")),  # 'namespace="polls"' removed
    ...,
]
```

*`polls/urls.py`*

```python
app_name = "polls"  # added
urlpatterns = [...]
```

这个变化还意味着旧的包含 `AdminSite` 实例的方式已经被弃用。相反，直接将 `admin.site.urls` 传递给 `django.conf.urls.url()`：

*`urls.py`*

```python
from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r"^admin/", admin.site.urls),
]
```

### 如果设置实例命名空间，需要提供 URL 应用程序命名空间。

在过去，没有应用程序命名空间的实例命名空间会起到与应用程序命名空间相同的作用，但如果存在相同名称的应用程序命名空间，无法对模式进行反向操作。指定实例命名空间的包含（includes）要求被包含的 URLconf 设置应用程序命名空间。

### `contrib.auth` 视图的 `current_app` 参数

`django.contrib.auth.views` 中的所有视图都具有以下结构：

```text
def view(request, ..., current_app=None, ...):

    ...

    if current_app is not None:
        request.current_app = current_app

    return TemplateResponse(request, template_name, context)
```

从 Django 1.8 开始，`current_app` 已设置在 `request` 对象上。为了保持一致性，这些视图将要求调用者在 `request` 上设置 `current_app`，而不是将其作为单独的参数传递。

### `django.contrib.gis.geoip`

[`django.contrib.gis.geoip2`](/zh-hans/5.1/ref/contrib/gis/geoip2/#module-django.contrib.gis.geoip2) 模块取代了 `django.contrib.gis.geoip`。新模块提供了类似的 API，但不提供旧的 GeoIP-Python API 兼容方法。

### 杂项

- `django.dispatch.signals.Signal.disconnect()` 中的 `weak` 参数已被弃用，因为它没有效果。
- `django.db.backends.base.BaseDatabaseOperations` 的 `check_aggregate_support()` 方法已被弃用，并将在 Django 2.0 中移除。应该改用更通用的 `check_expression_support()`。
- `django.forms.extras` 已被弃用。你可以在 `django.forms.widgets` （或简单地在 `django.forms` 中）找到 [`SelectDateWidget`](/zh-hans/5.1/ref/forms/widgets/#django.forms.SelectDateWidget)。
- 私有 API `django.db.models.fields.add_lazy_relation()` 已被弃用。
- `django.contrib.auth.tests.utils.skipIfCustomUser()` 装饰器已被弃用。随着 Django 1.6 中的测试发现变化，不再将 `django.contrib` 应用程序的测试作为用户项目的一部分运行。因此，在 `django.contrib.auth` 中不再需要使用 `@skipIfCustomUser` 装饰器来装饰测试。
- 如果你自定义了一些 [错误处理程序](/zh-hans/5.1/ref/views/#error-views)，那些只有一个请求参数的视图签名已经被弃用。这些视图现在还应该接受一个名为 `exception` 的第二个位置参数。
- `django.utils.feedgenerator.Atom1Feed.mime_type` 和 `django.utils.feedgenerator.RssFeed.mime_type` 属性已被弃用，建议使用 `content_type` 代替。
- [`Signer`](/zh-hans/5.1/topics/signing/#django.core.signing.Signer) 现在如果使用无效的分隔符会发出警告。这在 Django 1.10 中将变成异常。
- `django.db.models.Field._get_val_from_obj()` 已被弃用，应使用 `Field.value_from_object()`。
- `django.template.loaders.eggs.Loader` 已被弃用，因为不建议将应用程序作为 eggs 分发。
- `SimpleTestCase.assertRaisesMessage()` 中的 `callable_obj` 关键字参数已被弃用。请将可调用对象作为位置参数传递。
- 在 `ModelAdmin` 方法中的 `allow_tags` 属性已被弃用。在构建方法的返回值时，改用 [`format_html()`](/zh-hans/5.1/ref/utils/#django.utils.html.format_html)、[`format_html_join()`](/zh-hans/5.1/ref/utils/#django.utils.html.format_html_join) 或 [`mark_safe()`](/zh-hans/5.1/ref/utils/#django.utils.safestring.mark_safe)。
- `SyndicationFeed.add_item()` 中的 `enclosure` 关键字参数已被弃用。改用新的 `enclosures` 参数，它接受一个 `Enclosure` 对象的列表，而不是单个对象。
- `django.template.loader.LoaderOrigin` 和 `django.template.base.StringOrigin` 对于 `django.template.base.Origin` 的别名已被弃用。

## 在 1.9 版本中移除的功能。

这些特性已经达到了它们的弃用周期的尽头，将在 Django 1.9 中被移除。详情请参见 [在 1.7 中被废弃的功能](/zh-hans/5.1/releases/1.7/#deprecated-features-1-7)，包括如何删除对这些特性的使用。

- `django.utils.dictconfig` 已被移除。
- `django.utils.importlib` 已被移除。
- `django.utils.tzinfo` 已被移除。
- `django.utils.unittest` 已被移除。
- `syncdb` 命令已被移除。
- `django.db.models.signals.pre_syncdb` 和 `django.db.models.signals.post_syncdb` 已被移除。
- 数据库路由器上的 `allow_syncdb` 支持已被移除。
- 自动同步没有迁移的应用已被移除。对于所有应用程序，迁移是强制性的，除非你传递 [`migrate --run-syncdb`](/zh-hans/5.1/ref/django-admin/#cmdoption-migrate-run-syncdb) 选项。
- 对于没有迁移的应用程序，已移除了 SQL 管理命令：`sql`、`sqlall`、`sqlclear`、`sqldropindexes` 和 `sqlindexes`。
- 已移除自动加载 `initial_data` fixtures 和初始 SQL 数据的支持。
- 所有模型都需要在一个已安装的应用程序内定义，或者声明一个明确的 [`app_label`](/zh-hans/5.1/ref/models/options/#django.db.models.Options.app_label)。此外，在应用程序加载之前不能导入它们。特别是，在应用程序的根包内不能导入模型。
- 模型和表单的 `IPAddressField` 已被移除。为了与历史迁移兼容，仍然保留了一个存根字段。
- 不再支持 `AppCommand.handle_app()`。
- 无法再从 `django.contrib.sites.models` 导入 `RequestSite` 和 `get_current_site()`。
- 通过 `runfcgi` 管理命令的 FastCGI 支持已被移除。
- `django.utils.datastructures.SortedDict` 已被移除。
- `ModelAdmin.declared_fieldsets` 已被移除。
- 提供向后兼容性的 `util` 模块已被移除：

  - `django.contrib.admin.util`
  - `django.contrib.gis.db.backends.util`
  - `django.db.backends.util`
  - `django.forms.util`
- `ModelAdmin.get_formsets` 已被移除。
- 用于将 `BaseMemcachedCache._get_memcache_timeout()` 方法重命名为 `get_backend_timeout()` 的向后兼容 shims 已被移除。
- [`dumpdata`](/zh-hans/5.1/ref/django-admin/#django-admin-dumpdata) 的 `--natural` 和 `-n` 选项已被移除。
- `serializers.serialize()` 的 `use_natural_keys` 参数已被移除。
- 私有 API `django.forms.forms.get_declared_fields()` 已被移除。
- 使用 `SplitDateTimeWidget` 与 `DateTimeField` 的能力已被移除。
- `WSGIRequest.REQUEST` 属性已被移除。
- 类 `django.utils.datastructures.MergeDict` 已被移除。
- `zh-cn` 和 `zh-tw` 语言代码已被移除。
- 内部的 `django.utils.functional.memoize()` 已被移除。
- `django.core.cache.get_cache` 已被移除。
- `django.db.models.loading` 已被移除。
- 不再支持将可调用参数传递给查询集。
- `BaseCommand.requires_model_validation` 被移除，取而代之的是 `requires_system_checks`。管理器验证器被管理器检查取代。
- `ModelAdmin.validator_class` 和 `default_validator_class` 属性已被移除。
- `ModelAdmin.validate()` 已被移除。
- `django.db.backends.DatabaseValidation.validate_field` 被移除，取而代之的是 `check_field` 方法。
- `validate` 管理命令已被移除。
- `django.utils.module_loading.import_by_path` 被移除，取而代之的是 `django.utils.module_loading.import_string`。
- `ssi` 和 `url` 模板标签已从 `future` 模板标签库中移除。
- `django.utils.text.javascript_quote()` 已被移除。
- 不再支持将数据库测试设置作为独立的条目出现在数据库设置中，并以 `TEST_` 为前缀。
- `cache_choices` 选项已被移除，不再适用于 [`ModelChoiceField`](/zh-hans/5.1/ref/forms/fields/#django.forms.ModelChoiceField) 和 [`ModelMultipleChoiceField`](/zh-hans/5.1/ref/forms/fields/#django.forms.ModelMultipleChoiceField)。
- [`RedirectView.permanent`](/zh-hans/5.1/ref/class-based-views/base/#django.views.generic.base.RedirectView.permanent) 属性的默认值已从 `True` 更改为 `False`。
- `django.contrib.sitemaps.FlatPageSitemap` 已被移除，取而代之的是 `django.contrib.flatpages.sitemaps.FlatPageSitemap`。
- 私有 API `django.test.utils.TestTemplateLoader` 已被移除。
- `django.contrib.contenttypes.generic` 模块已被移除。
