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

*2012 年 3 月 23 日*

欢迎来到 Django 1.4 版本！

这些发布说明涵盖了 [新特性](#whats-new-1-4)，以及从 Django 1.3 或更早版本升级时需要注意的一些 [不向后兼容的变更](#backwards-incompatible-1-4)。我们还放弃了一些功能，详细信息在 [我们的弃用计划](/zh-hans/5.2/internals/deprecation/#deprecation-removed-in-1-4) 中说明，并且我们已经 [开始了一些功能的弃用过程](#deprecated-features-1-4)。

## 概况

Django 1.4 中最重要的新特性是在处理日期/时间时提供了对时区的支持。当启用时，Django 将在 UTC 中存储日期/时间，内部使用时区感知的对象，并将它们翻译为用户的本地时区以供显示。

如果您正在将现有项目升级到 Django 1.4，切换到时区感知模式可能需要一些注意：新模式不允许以前被接受的一些相当松散的行为。我们鼓励任何升级的用户查看 [时区迁移指南](/zh-hans/5.2/topics/i18n/timezones/#time-zones-migration-guide) 和 [时区常见问题解答](/zh-hans/5.2/topics/i18n/timezones/#time-zones-faq)，以获取有用的提示。

Django 1.4 中其他值得关注的新功能包括：

- ORM 改进方面有很多改进，包括 [SELECT FOR UPDATE 支持](#select-for-update-support)，能够以 [bulk insert](#bulk-insert) 的方式插入大型数据集以提高性能，以及 [QuerySet.prefetch\_related](#queryset-prefetch-related)，这是一种在 [`select_related()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.select_related) 不适用的情况下批量加载相关对象的方法。
- 一些不错的安全性增强功能，包括 [改进的密码哈希算法](#improved-password-hashing) （支持 [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) 和 [bcrypt](https://en.wikipedia.org/wiki/Bcrypt)），新的 [加密签名工具](#tools-for-cryptographic-signing)，几个 [CSRF 改进](#csrf-improvements)，以及 [简单的点击劫持保护](#simple-clickjacking-protection)。
- [更新的默认项目布局和 manage.py](#updated-default-project-layout-and-manage-py) ，去除了以前版本中的"魔法"。对于那些不喜欢新布局的人，可以使用 [自定义项目和应用模板](#custom-project-and-app-templates)。
- [对于浏览器内测试框架的支持](#support-for-in-browser-testing-frameworks) （如 [Selenium](https://www.selenium.dev/)）。
- ... 还有很多内容；[查看下文](#what-s-new-in-django-1-4)！

在尽可能的情况下，我们尝试以符合 [我们的 API 稳定性政策](/zh-hans/5.2/misc/api-stability/) 的方式引入新功能。然而，与以前的版本一样，Django 1.4 也带有一些轻微的 [不兼容变更](#backwards-incompatible-1-4)；从以前版本的 Django 升级的用户应该仔细阅读该列表。

## Python 兼容性

Django 1.4 已放弃对 Python 2.4 的支持。现在要求的最低 Python 版本为 2.5 。 Django 在 Python 2.5 、 2.6 和 2.7 上经过测试并得到支持。

这个变更应该只会影响到少数 Django 用户，因为大多数操作系统厂商今天都默认安装 Python 2.5 或更新版本。然而，如果你仍然在使用 Python 2.4，你将需要继续使用 Django 1.3，直到你可以升级。根据 [我们的支持政策](/zh-hans/5.2/internals/release-process/)，Django 1.3 将在 Django 1.5 发布之前继续获得安全支持。

目前 Django 不支持 Python 3.x 。在 Django 1.4 发布之前的某个时刻，我们计划发布一份文件，概述我们废弃 Python 2.x 并转向 Python 3.x 的完整时间表。

## Django 1.4 新特性

### 时区支持

在以前的版本中，Django 使用了“天真”的日期/时间（也就是没有关联时区的日期/时间），让每个开发者来解释给定的日期/时间“真正的含义”。这可能导致各种微妙的时区相关错误。

在 Django 1.4 中，您现在可以将 Django 切换到更正确的、具有时区感知的模式。在此模式下，Django 将日期和时间信息以 UTC 格式存储在数据库中，内部使用具有时区感知的 datetime 对象，并在模板和表单中将它们转换为最终用户的时区。使用此功能的原因包括：

- 为世界各地的用户自定义日期和时间显示。
- 以 UTC 格式存储日期时间以实现数据库的可移植性和互操作性。（这个论点不适用于 PostgreSQL，因为在 Django 1.3 中，它已经存储了带有时区信息的时间戳。）
- 避免在夏令时转换期间出现数据损坏问题。

在使用 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 创建的新项目中，默认启用了时区支持。如果你想在现有项目中使用这个功能，请阅读 [迁移指南](/zh-hans/5.2/topics/i18n/timezones/#time-zones-migration-guide)。如果遇到问题，可以参考有用的 [常见问题解答](/zh-hans/5.2/topics/i18n/timezones/#time-zones-faq)。

### 支持基于浏览器的测试框架

Django 1.4 支持与浏览器测试框架（如 [Selenium](https://www.selenium.dev/)）的集成。新的 [`django.test.LiveServerTestCase`](/zh-hans/5.2/topics/testing/tools/#django.test.LiveServerTestCase) 基类允许你更全面地测试你的网站前端和后端之间的交互。有关更多详细信息和具体示例，请参阅 [`文档`](/zh-hans/5.2/topics/testing/tools/#django.test.LiveServerTestCase)。

### 更新了默认项目布局和 `manage.py`。

Django 1.4 附带了一个更新后的默认项目布局和 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 管理命令的 `manage.py` 文件。这些修复了之前的 `manage.py` 处理 Python 导入路径的一些问题，导致了重复导入、从开发环境切换到部署环境的困难以及其他难以调试的路径问题。

之前的 `manage.py` 调用了现在已弃用的函数，因此升级到 Django 1.4 的项目应该更新他们的 `manage.py`。（旧式的 `manage.py` 将在 Django 1.6 之前继续像以前一样工作。在 1.5 中，它将引发 `DeprecationWarning`）。

推荐使用的新 `manage.py` 文件应该如下所示：

```
#!/usr/bin/env python
import os, sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")

    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)
```

`{{ project_name }}` 应该替换为实际项目的 Python 包名称。

如果项目中导入或引用了设置、URL 配置和应用程序时使用项目名称前缀（例如 `myproject.settings`，`ROOT_URLCONF = "myproject.urls"` 等），新的 `manage.py` 需要移动到上一级目录，以便它位于项目包之外，而不是与 `settings.py` 和 `urls.py` 并列。

例如，以下布局：

```text
manage.py
mysite/
    __init__.py
    settings.py
    urls.py
    myapp/
        __init__.py
        models.py
```

你可以导入 `mysite.settings`、`mysite.urls` 和 `mysite.myapp`，但不能导入 `settings`、`urls` 或 `myapp` 作为顶级模块。

作为顶级模块导入的任何内容都可以放在新的 `manage.py` 旁边。例如，要将 `myapp` 与项目模块解耦并将其导入为 `myapp`，请将其放在 `mysite/` 目录之外：

```text
manage.py
myapp/
    __init__.py
    models.py
mysite/
    __init__.py
    settings.py
    urls.py
```

如果相同的代码在不一致的地方导入（有些地方使用项目前缀，有些地方不使用），在切换到新的 `manage.py` 时需要清理导入语句。

### 自定义项目和应用模板

现在，[`startapp`](/zh-hans/5.2/ref/django-admin/#django-admin-startapp) 和 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 管理命令都有一个 `--template` 选项，用于指定自定义应用程序或项目模板的路径或 URL。

例如，当你运行以下命令时，Django 将使用 `/path/to/my_project_template` 目录：

```shell
django-admin.py startproject --template=/path/to/my_project_template myproject
```

现在，你也可以将目标目录作为 [`startapp`](/zh-hans/5.2/ref/django-admin/#django-admin-startapp) 和 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 的第二个参数提供：

```shell
django-admin.py startapp myapp /path/to/new/app
django-admin.py startproject myproject /path/to/new/project
```

有关更多信息，请参阅 [`startapp`](/zh-hans/5.2/ref/django-admin/#django-admin-startapp) 和 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 的文档。

### 改进的 WSGI 支持

[`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 管理命令现在会在初始项目布局中添加一个 `wsgi.py` 模块，其中包含一个简单的 WSGI 应用程序，可以用于 [使用 WSGI 应用服务器部署](/zh-hans/5.2/howto/deployment/wsgi/)。

内置的开发服务器 [`runserver`](/zh-hans/5.2/ref/django-admin/#django-admin-runserver) 现在支持使用外部定义的 WSGI 可调用函数，这使得可以使用与部署相同的 WSGI 配置来运行 `runserver`。新的 [`WSGI_APPLICATION`](/zh-hans/5.2/ref/settings/#std-setting-WSGI_APPLICATION) 设置允许你配置 [`runserver`](/zh-hans/5.2/ref/django-admin/#django-admin-runserver) 使用哪个 WSGI 可调用函数。

（`runfcgi` 管理命令也会在内部包装通过 [`WSGI_APPLICATION`](/zh-hans/5.2/ref/settings/#std-setting-WSGI_APPLICATION) 配置的 WSGI 可调用函数。）

### `SELECT FOR UPDATE` 支持

Django 1.4 包含了一个 [`QuerySet.select_for_update()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update) 方法，它生成一个 `SELECT ... FOR UPDATE` SQL 查询。这将锁定行，直到事务结束，这意味着其他事务无法修改或删除与 `FOR UPDATE` 查询匹配的行。

有关更多详细信息，请参阅 [`select_for_update()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.select_for_update) 的文档。

### ORM 中的 `Model.objects.bulk_create`

这种方法让您能够更高效地创建多个对象。如果您有很多对象，这可能会带来显著的性能提升。

Django 在内部使用了这种方法，这意味着某些操作（如测试套件的数据库设置）因此也获得了性能提升。

请查看 [`bulk_create()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) 文档以获取更多信息。

### `QuerySet.prefetch_related`

类似于 [`select_related()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.select_related)，但具有不同策略和更广泛的范围，[`prefetch_related()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related) 已经添加到 [`QuerySet`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet) 中。这个方法返回一个新的 `QuerySet`，将在查询开始被评估时以单个批次的方式预取每个指定的相关查找。与 `select_related` 不同，它在 Python 中执行连接操作，而不是在数据库中执行，并支持多对多关系、`GenericForeignKey` 等。这允许您解决一个非常常见的性能问题，即如果主要 `QuerySet` 上的对象每个都有许多相关对象需要获取，那么您的代码最终会执行 O(n) 数据库查询（或更糟）。

### 改进的密码散列处理

Django 的认证系统（`django.contrib.auth`）使用单向算法存储密码。Django 1.3 使用 [SHA1](https://en.wikipedia.org/wiki/SHA1) 算法，但随着处理器速度的增加和理论攻击的出现，SHA1 的安全性不如我们希望的那么高。因此，Django 1.4 引入了一个新的密码存储系统：默认情况下，Django 现在使用 [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) 算法（由 [NIST](https://csrc.nist.gov/publications/detail/sp/800-132/final) 推荐）。您还可以轻松选择不同的算法（包括流行的 [bcrypt](https://en.wikipedia.org/wiki/Bcrypt) 算法）。有关更多详细信息，请参阅 [Django 如何存储密码](/zh-hans/5.2/topics/auth/passwords/#auth-password-storage)。

### HTML5 文档类型定义（doctype）

我们已经将管理员和其他捆绑模板切换为使用 HTML5 文档类型定义。尽管 Django 会小心地保持与旧浏览器的兼容性，但这一变化意味着您可以在管理员页面中使用所需的任何 HTML5 功能，而无需失去 HTML 有效性或覆盖提供的模板以更改文档类型定义。

### 管理员界面的列表过滤器

在 Django 1.4 之前，[`admin`](/zh-hans/5.2/ref/contrib/admin/#module-django.contrib.admin) 应用程序允许您通过指定字段查找来指定更改列表过滤器，但不允许您创建自定义过滤器。这已经得到了纠正，并引入了一个简单的 API（以前在内部使用，被称为 "FilterSpec"）。有关更多详细信息，请参阅 [`list_filter`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter) 的文档。

### 管理员界面的多重排序功能

管理界面的更改列表现在支持在多个列上进行排序。它尊重 [`ordering`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.ordering) 属性的所有元素，并且通过单击标题进行多列排序的行为设计得类似于桌面 GUI。我们还添加了一个 [`get_ordering()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_ordering) 方法，用于动态指定排序顺序（即，根据请求的不同情况）。

### 新的 `ModelAdmin` 方法

我们在 [`ModelAdmin`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin) 中添加了一个 [`save_related()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_related) 方法，以便更容易自定义在管理员中保存相关对象的方式。

另外两个新的 [`ModelAdmin`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin) 方法，[`get_list_display()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_list_display) 和 [`get_list_display_links()`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_list_display_links)，允许动态自定义在管理员更改列表上显示的字段和链接。

### 管理员内联遵循用户权限

管理员内联现在只允许用户具有权限的操作。对于具有自动创建的中间模型的 `ManyToMany` 关系（该模型没有自己的权限），相关模型的更改权限确定用户是否具有添加、更改或删除关系的权限。

### 加密签名工具

Django 1.4 既添加了用于签名值的低级 API，也添加了用于设置和读取签名 Cookie 的高级 API，这是 Web 应用程序中签名的最常见用途之一。

有关更多信息，请查看 [加密签名](/zh-hans/5.2/topics/signing/) 文档。

### 基于 Cookie 的会话后端

Django 1.4 引入了一种基于 Cookie 的会话后端，它使用 [加密签名](/zh-hans/5.2/topics/signing/) 工具来将会话数据存储在客户端的浏览器中。

> **Warning**
>
> 会话数据由服务器签名并验证，但不加密。这意味着用户可以查看存储在会话中的任何数据，但不能更改它。在使用此后端之前，请阅读文档以进一步了解。

有关更多信息，请查看 [基于 Cookie 的会话后端](/zh-hans/5.2/topics/http/sessions/#cookie-session-backend) 文档。

### 新的表单向导

以前的 `FormWizard` 从 `django.contrib.formtools` 已经被一个基于 Django 1.3 引入的基于类的视图的新实现替代。它具有可插拔的存储 API，并且不需要向前的每个步骤传递隐藏字段。

Django 1.4 附带了一个基于会话的存储后端和一个基于 Cookie 的存储后端。后者还使用了在 Django 1.4 中引入的 [加密签名](/zh-hans/5.2/topics/signing/) 工具来将向导的状态存储在用户的 Cookie 中。

### `reverse_lazy`

新增了一个惰性评估版本的 `reverse()`，允许在项目的 URL 配置加载之前使用 URL 反转。

### 翻译 URL 模式

Django 现在可以在使用新的 [`i18n_patterns()`](/zh-hans/5.2/topics/i18n/translation/#django.conf.urls.i18n.i18n_patterns) 辅助函数时在 URL 模式中查找语言前缀。还可以使用 `django.utils.translation.ugettext_lazy()` 定义可翻译的 URL 模式。有关语言前缀以及如何国际化 URL 模式的更多信息，请参阅 [国际化：在 URL 模式中](/zh-hans/5.2/topics/i18n/translation/#url-internationalization)。

### 对于 `{% trans %}` 和 `{% blocktrans %}`，现在支持上下文翻译。

在 Django 1.3 中通过 `pgettext` 函数引入的 [上下文翻译](/zh-hans/5.2/topics/i18n/translation/#contextual-markers) 支持已经扩展到 [`trans`](/zh-hans/5.2/topics/i18n/translation/#std-templatetag-trans) 和 [`blocktrans`](/zh-hans/5.2/topics/i18n/translation/#std-templatetag-blocktrans) 模板标签，使用了新的 `context` 关键字。

### 可自定义的 `SingleObjectMixin` URLConf kwargs

为了允许自定义用于单个对象通用视图的 URLconf 关键字参数，新增了两个新属性：[`pk_url_kwarg`](/zh-hans/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.pk_url_kwarg) 和 [`slug_url_kwarg`](/zh-hans/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin.slug_url_kwarg)，它们被添加到 [`SingleObjectMixin`](/zh-hans/5.2/ref/class-based-views/mixins-single-object/#django.views.generic.detail.SingleObjectMixin) 中。

### 赋值模板标签

新增了一个名为 `assignment_tag` 的辅助函数到 `template.Library`，用于简化创建模板标签并将数据存储在指定的上下文变量中。

### 模板标签辅助函数现在支持 `*args` 和 `**kwargs`

The [simple\_tag](/zh-hans/5.2/howto/custom-template-tags/#howto-custom-template-tags-simple-tags),
[inclusion\_tag](/zh-hans/5.2/howto/custom-template-tags/#howto-custom-template-tags-inclusion-tags) and newly
introduced `assignment_tag` template helper functions may now accept any
number of positional or keyword arguments. For example:

```
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
    warning = kwargs["warning"]
    profile = kwargs["profile"]
    ...
    return ...
```

然后，在模板中，可以将任意数量的参数传递给模板标签。例如：

```html+django
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
```

### 在 `TEMPLATE_DEBUG` 模式下不会包装异常

在以前的 Django 版本中，无论何时 `TEMPLATE_DEBUG` 设置为 `True`，在模板渲染期间引发的任何异常（甚至与模板语法无关的异常）都会被包装在 `TemplateSyntaxError` 中并重新引发。这是为了在调试 500 页面中提供详细的模板源位置信息。

在 Django 1.4 中，不再包装异常。相反，原始异常会带有源信息的注释。这意味着无论 `TEMPLATE_DEBUG` 的值如何，现在捕获模板渲染中的异常都是一致的，而且不需要捕获和解包 `TemplateSyntaxError` 以捕获其他错误。

### `truncatechars` 模板过滤器

这个新的过滤器将字符串截断，使其不超过指定的字符数。截断的字符串以可翻译的省略号序列（"..."）结尾。有关更多详细信息，请参阅 [`truncatechars`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-truncatechars) 的文档。

### `static` 模板标签

[`staticfiles`](/zh-hans/5.2/ref/contrib/staticfiles/#module-django.contrib.staticfiles) contrib 应用有一个新的 `static` 模板标签，用于引用使用 `STATICFILES_STORAGE` 存储后端保存的文件。它使用存储后端的 `url` 方法，因此支持高级功能，例如 [从云服务提供文件](/zh-hans/5.2/howto/static-files/deployment/#staticfiles-from-cdn)。

### `CachedStaticFilesStorage` 存储后端

现在，[`staticfiles`](/zh-hans/5.2/ref/contrib/staticfiles/#module-django.contrib.staticfiles) 贡献应用程序具有一个 `django.contrib.staticfiles.storage.CachedStaticFilesStorage` 后端，通过将文件内容的 MD5 哈希附加到文件名中来缓存它保存的文件（在运行 [`collectstatic`](/zh-hans/5.2/ref/contrib/staticfiles/#django-admin-collectstatic) 管理命令时）。例如，文件 `css/styles.css` 也将保存为 `css/styles.55e7cbb9ba48.css`。

### 简单的点击劫持保护

我们添加了一个中间件，通过使用 `X-Frame-Options` 头提供了简单的防止 [clickjacking](https://en.wikipedia.org/wiki/Clickjacking) 的保护。出于向后兼容性的原因，默认情况下未启用它，但您几乎肯定希望 [启用它](/zh-hans/5.2/ref/clickjacking/) 以帮助修复支持该头的浏览器中的安全漏洞。

### CSRF 改进

我们对 CSRF 功能进行了各种改进，包括 [`ensure_csrf_cookie()`](/zh-hans/5.2/ref/csrf/#django.views.decorators.csrf.ensure_csrf_cookie) 装饰器，它可以帮助处理 AJAX 密集的站点；对 PUT 和 DELETE 请求的保护；以及 [`CSRF_COOKIE_SECURE`](/zh-hans/5.2/ref/settings/#std-setting-CSRF_COOKIE_SECURE) 和 [`CSRF_COOKIE_PATH`](/zh-hans/5.2/ref/settings/#std-setting-CSRF_COOKIE_PATH) 设置，它们可以提高 CSRF 保护的安全性和实用性。有关更多信息，请参阅 [CSRF 文档](/zh-hans/5.2/ref/csrf/)。

### 错误报告过滤

我们添加了两个函数装饰器，[`sensitive_variables()`](/zh-hans/5.2/howto/error-reporting/#django.views.decorators.debug.sensitive_variables) 和 [`sensitive_post_parameters()`](/zh-hans/5.2/howto/error-reporting/#django.views.decorators.debug.sensitive_post_parameters)，允许指定可能包含敏感信息并且应该从错误报告中过滤掉的本地变量和 POST 参数。

现在，对于某些视图（`login`、`password_reset_confirm`、`password_change` 和 [`django.contrib.auth.views`](/zh-hans/5.2/topics/auth/default/#module-django.contrib.auth.views) 中的 `add_view`，以及管理员应用程序中的 `user_change_password`），所有 POST 参数都会被系统地从错误报告中过滤掉，以防止敏感信息（如用户密码）的泄漏。

您可以通过编写 [自定义过滤器](/zh-hans/5.2/howto/error-reporting/#custom-error-reports) 来覆盖或自定义默认的过滤方式。有关更多信息，请参阅 [过滤错误报告](/zh-hans/5.2/howto/error-reporting/#filtering-error-reports) 文档。

### 扩展的 IPv6 支持

Django 1.4 现在可以更好地处理 IPv6 地址，引入了新的 [`GenericIPAddressField`](/zh-hans/5.2/ref/models/fields/#django.db.models.GenericIPAddressField) 模型字段，[`GenericIPAddressField`](/zh-hans/5.2/ref/forms/fields/#django.forms.GenericIPAddressField) 表单字段以及验证器 [`validate_ipv46_address`](/zh-hans/5.2/ref/validators/#django.core.validators.validate_ipv46_address) 和 [`validate_ipv6_address`](/zh-hans/5.2/ref/validators/#django.core.validators.validate_ipv6_address)。

### 测试中的 HTML 比较

在 [`django.test`](/zh-hans/5.2/topics/testing/overview/#module-django.test) 中的基类现在具有一些帮助程序，可以比较 HTML，而不会受到不相关的空格差异、参数引用/顺序以及自闭标签的关闭的干扰。您可以使用新的 [`assertHTMLEqual()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertHTMLEqual) 和 [`assertHTMLNotEqual()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertHTMLNotEqual) 断言直接比较 HTML，或者使用 `html=True` 标志与 [`assertContains()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertContains) 和 [`assertNotContains()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertNotContains) 来测试客户端的响应是否包含给定的 HTML 片段。有关更多信息，请参阅 [断言文档](/zh-hans/5.2/topics/testing/tools/#assertions)。

### 两个新的日期格式字符串

新增了两个 [`date`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-date) 格式，可用于模板过滤器、模板标签和 [本地格式化](/zh-hans/5.2/topics/i18n/formatting/)：

- `e` -- 给定日期时间对象的时区名称
- `o` -- ISO 8601 年份编号

请确保在您的 [自定义格式文件](/zh-hans/5.2/topics/i18n/formatting/#custom-format-files) 中更新包含格式字符串中的 `e` 或 `o` 的部分。例如，先前的西班牙本地化格式仅对 `d` 格式字符进行了转义：

```
DATE_FORMAT = r"j \de F \de Y"
```

但现在它还需要转义 `e` 和 `o`：

```
DATE_FORMAT = r"j \d\e F \d\e Y"
```

有关更多信息，请参阅 [`date`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-date) 文档。

### 次要特性

Django 1.4 还包括一些值得注意的较小改进：

- 技术性 500 错误页面中更易用的堆栈跟踪。堆栈跟踪中引用 Django 框架代码的帧会变暗，而应用程序代码中的帧会稍微突出。这个改变使得在堆栈跟踪中查找应用程序代码的问题变得更容易。
- 在 PostgreSQL 中支持 [表空间](/zh-hans/5.2/topics/db/tablespaces/)。
- 可自定义 [`simple_tag()`](/zh-hans/5.2/howto/custom-template-tags/#django.template.Library.simple_tag) 的名称。
- 在文档中，有一个有用的 [安全概述](/zh-hans/5.2/topics/security/) 页面。
- `django.contrib.auth.models.check_password` 函数已移动到 [`django.contrib.auth.hashers`](/zh-hans/5.2/topics/auth/passwords/#module-django.contrib.auth.hashers) 模块。从旧位置导入仍然可以工作，但您应该更新您的导入语句。
- 现在，[`collectstatic`](/zh-hans/5.2/ref/contrib/staticfiles/#django-admin-collectstatic) 管理命令具有一个 `--clear` 选项，用于在复制或链接静态文件之前删除目标位置的所有文件。
- 现在可以在使用带有 InnoDB 数据库引擎的 MySQL 时加载包含前向引用的固定数据。
- 新增了一个新的 403 响应处理程序，名称为 `'django.views.defaults.permission_denied'`。您可以通过设置 [`django.conf.urls.handler403`](/zh-hans/5.2/ref/urls/#django.conf.urls.handler403) 的值来设置自己的处理程序。有关更多信息，请参阅 [403 (HTTP Forbidden) 视图](/zh-hans/5.2/ref/views/#http-forbidden-view) 的文档。
- [`makemessages`](/zh-hans/5.2/ref/django-admin/#django-admin-makemessages) 命令现在使用一个新的、更准确的词法分析器，[JsLex](https://pypi.org/project/jslex/)，用于从 JavaScript 文件中提取可翻译的字符串。
- [`trans`](/zh-hans/5.2/topics/i18n/translation/#std-templatetag-trans) 模板标签现在接受一个可选的 `as` 参数，以便能够检索翻译字符串而不显示它，而是设置一个模板上下文变量。
- [`if`](/zh-hans/5.2/ref/templates/builtins/#std-templatetag-if) 模板标签现在支持 `{% elif %}` 子句。
- 如果您的 Django 应用程序位于代理之后，您可能会发现新的 [`SECURE_PROXY_SSL_HEADER`](/zh-hans/5.2/ref/settings/#std-setting-SECURE_PROXY_SSL_HEADER) 设置很有用。它解决了代理将请求通过 HTTPS 进行传递的问题。但只有在知道自己在做什么的情况下才使用此设置。
- 当 [`DEBUG`](/zh-hans/5.2/ref/settings/#std-setting-DEBUG) 为 `True` 时，Django 在检测到请求源自 JavaScript 代码时，会向客户端发送新的 HTTP 500 状态码内部错误页面的纯文本版本（使用 `is_ajax()` 进行检测）。

  与其 HTML 对应部分一样，它包含了关于应用程序状态的不同信息片段。

  这将使得在调试与客户端 JavaScript 交互时更容易阅读。
- 新增了 [`makemessages --no-location`](/zh-hans/5.2/ref/django-admin/#cmdoption-makemessages-no-location) 选项。
- 更改了 `locmem` 缓存后端，以使用 `pickle.HIGHEST_PROTOCOL` 以提高与其他缓存后端的兼容性。
- 在 ORM 中添加了生成包含 `DISTINCT ON` 的 `SELECT` 查询的支持。

  `distinct()` 方法现在接受一个可选的模型字段名称列表。如果指定了这些字段，则 `DISTINCT` 语句将限定在这些字段上。这仅在 PostgreSQL 中支持。

  有关更多详细信息，请参阅 [`distinct()`](/zh-hans/5.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct) 的文档。
- 如果在您的 `urls.py` 中包含一个名称为 `'admin_password_reset'` 的 URL，管理员登录页面将添加一个密码重置链接，因此现在更容易使用内置的密码重置机制并使其可用。有关详细信息，请参阅 [增加密码重置功能](/zh-hans/5.2/ref/contrib/admin/#auth-password-reset)。
- MySQL 数据库后端现在可以利用 MySQL 5.0.3 或更新版本的 InnoDB 存储引擎实现的保存点功能。
- 现在，可以像常规表单集合一样，将初始值传递给模型表单，这些模型表单是从工厂函数 `modelformset_factory` 和 `inlineformset_factory` 返回的，它们分别是模型表单集合和内联模型表单集合的一部分。但是，初始值仅适用于额外的表单，即不绑定到现有模型实例的表单。
- 现在，站点地图框架可以使用新的 [`Sitemap.protocol`](/zh-hans/5.2/ref/contrib/sitemaps/#django.contrib.sitemaps.Sitemap.protocol) 类属性处理 HTTPS 链接。
- 新增了一个 [`django.test.SimpleTestCase`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase)，它是 [`unittest.TestCase`](https://docs.python.org/3/library/unittest.html#unittest.TestCase) 的子类，比 [`django.test.TestCase`](/zh-hans/5.2/topics/testing/tools/#django.test.TestCase) 和相关的测试用例更轻量。它可以在不需要访问数据库的测试中使用。请参阅 [Django 单元测试类的层次结构](/zh-hans/5.2/topics/testing/tools/#testcase-hierarchy-diagram)。

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

### SECRET\_KEY 设置是必需的

使用空或已知的 [`SECRET_KEY`](/zh-hans/5.2/ref/settings/#std-setting-SECRET_KEY) 运行 Django 会禁用许多 Django 的安全保护功能，并可能导致远程代码执行漏洞。任何 Django 站点都不应该在没有 [`SECRET_KEY`](/zh-hans/5.2/ref/settings/#std-setting-SECRET_KEY) 的情况下运行。

在 Django 1.4 中，使用空的 [`SECRET_KEY`](/zh-hans/5.2/ref/settings/#std-setting-SECRET_KEY) 启动 Django 会引发 `DeprecationWarning`。在 Django 1.5 中，它将引发异常，并且 Django 将拒绝启动。这是因为在没有 [`SECRET_KEY`](/zh-hans/5.2/ref/settings/#std-setting-SECRET_KEY) 的情况下运行 Django 会导致严重后果，所以这个过程略有加速。

### `django.contrib.admin`

包含的管理应用程序 `django.contrib.admin` 长期以来都包含了一组默认的静态文件，如 JavaScript、图像和样式表。Django 1.3 添加了一个新的 contrib 应用程序 `django.contrib.staticfiles`，以一种通用的方式处理这些文件，并定义了应用程序中包含的静态文件的约定。

从 Django 1.4 开始，管理界面的静态文件也遵循这个约定，以使文件更容易部署。在 Django 的早期版本中，通常会定义一个 `ADMIN_MEDIA_PREFIX` 设置，指向 web 服务器上管理界面的静态文件所在的 URL。现在，这个设置已被弃用，并由更通用的设置 [`STATIC_URL`](/zh-hans/5.2/ref/settings/#std-setting-STATIC_URL) 取代。Django 现在期望在 URL `<STATIC_URL>/admin/` 下找到管理界面的静态文件。

如果您之前使用了 `ADMIN_MEDIA_PREFIX` 的 URL 路径（例如 `/media/`），只需确保 [`STATIC_URL`](/zh-hans/5.2/ref/settings/#std-setting-STATIC_URL) 和 [`STATIC_ROOT`](/zh-hans/5.2/ref/settings/#std-setting-STATIC_ROOT) 配置正确，并且您的 Web 服务器能够正确提供这些文件。开发服务器仍然像以前一样提供管理界面的文件。阅读 [静态文件 howto](/zh-hans/5.2/howto/static-files/) 以获取更多详细信息。

如果您的 `ADMIN_MEDIA_PREFIX` 设置为特定的域名（例如 `http://media.example.com/admin/`），请确保将您的 [`STATIC_URL`](/zh-hans/5.2/ref/settings/#std-setting-STATIC_URL) 设置为正确的 URL，例如 `http://media.example.com/`。

> **Warning**
>
> 如果您隐式依赖于 Django 源代码中管理界面静态文件的路径，您需要更新该路径。这些文件已从 `django/contrib/admin/media/` 移动到 `django/contrib/admin/static/admin/`。

### 管理支持的浏览器

Django 对于管理界面应用程序支持哪些浏览器一直没有明确的政策。我们的新政策正式规范了现有的做法：[YUI 的 A 级](https://github.com/yui/yui3/wiki/Graded-Browser-Support) 浏览器应提供完整功能的管理界面体验，但不再支持 Internet Explorer 6，这是一个显著的例外。

IE6 发布于 10 多年前，给现代 Web 开发带来了许多限制。这项政策的实际影响是，贡献者可以在不考虑这些限制的情况下自由地改进管理员界面。

这个新政策 **不会影响** 使用 Django 开发的网站。它仅适用于 Django 管理界面。请随意开发与各种浏览器兼容的应用程序。

### 移除了管理图标

为了改善管理界面的列表排序界面和 [`horizontal`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_horizontal) 和 [`vertical`](/zh-hans/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.filter_vertical) "filter" 小部件的性能和可用性，一些图标文件已被删除并组合到两个精灵文件中。

具体来说：`selector-add.gif`, `selector-addall.gif`, `selector-remove.gif`, `selector-removeall.gif`, `selector_stacked-add.gif` 和 `selector_stacked-remove.gif` 已合并到 `selector-icons.gif` 中；`arrow-up.gif` 和 `arrow-down.gif` 已合并到 `sorting-icons.gif` 中。

如果您使用这些图标来自定义管理员界面，那么您需要用自己的图标替换它们，或者从以前的版本中获取这些文件。

### 管理员表单中的 CSS 类名

为避免与其他常见 CSS 类名（例如 "button"）发生冲突，我们为主管理员表单、堆叠内联表单和表格内联单元格中的表单字段名自动生成的所有 CSS 类名添加了一个前缀（"field-"）。如果您之前使用普通字段名作为自定义样式或 JavaScript 转换的选择器，您需要在自定义样式表或 JavaScript 文件中考虑到这个前缀。

### 与旧版签名数据的兼容性

Django 1.3 更改了 Django 中多个地方使用的加密签名机制。尽管 Django 1.3 保留了接受由之前方法生成的哈希值的回退机制，但这些回退机制在 Django 1.4 中已被移除。

因此，如果您直接从 1.2 或更早版本升级到 Django 1.4，您可能会丢失/使使用旧方法加密签名的某些数据失效。为避免这种情况，请先使用 Django 1.3 一段时间，以便让签名数据自然过期。受影响的部分详细说明如下： 1 ) 忽略此建议的后果； 2 ) 为使数据过期或变得无关紧要，您需要运行 Django 1.3 的时间。

- `contrib.sessions` 数据完整性检查

  - 后果：用户将被登出，且会话数据将丢失。
  - 时间段：由 [`SESSION_COOKIE_AGE`](/zh-hans/5.2/ref/settings/#std-setting-SESSION_COOKIE_AGE) 定义。
- `contrib.auth` 密码重置哈希

  - 后果：升级前的密码重置链接将无法使用。
  - 时间段：由 `PASSWORD_RESET_TIMEOUT_DAYS` 定义。

与表单相关的哈希：它们的生命周期要短得多，仅与用户可能填写由升级前的 Django 实例生成的表单并尝试将其提交到升级后的 Django 实例的短暂窗口期相关。

- `contrib.comments` 表单安全哈希

  - 后果：用户将看到验证错误 "安全哈希失败。"
  - 时间周期：您预期用户填写评论表单所需的时间。
- `FormWizard` 安全哈希

  - 后果：用户将看到关于表单已过期的错误，并被退回到向导的第一页，迄今为止输入的数据将丢失。
  - 时间周期：您预期用户填写受影响表单所需的时间。
- CSRF 检查

  - 注意：这实际上是一个从 Django 1.1 回退，而不是 Django 1.2，仅在您从 1.1 升级时适用。
  - 后果：用户在任何受 CSRF 保护的 POST 表单中都会看到 403 错误。
  - 时间周期：您预期用户填写此类表单所需的时间。
- `contrib.auth` 用户密码升级哈希序列

  - 后果：在 1.4 版本中，每个用户的密码将在写入数据库时更新为更强的密码散列。这意味着如果您升级到 1.4 然后需要降级到 1.3，1.3 版本将无法读取更新后的密码。
  - 解决方法：在初始升级到 1.4 时将 [`PASSWORD_HASHERS`](/zh-hans/5.2/ref/settings/#std-setting-PASSWORD_HASHERS) 设置为使用您原始的密码哈希方式。确认您的应用在 Django 1.4 上运行良好且不需要回滚到 1.3 后，启用新的密码哈希方式。

### `django.contrib.flatpages`

从 1.4 版本开始，[`FlatpageFallbackMiddleware`](/zh-hans/5.2/ref/contrib/flatpages/#django.contrib.flatpages.middleware.FlatpageFallbackMiddleware) 仅在生成的 URL 引用现有的平面页面时才会添加尾随斜杠并重定向。例如，在以前的版本中，请求 `/notaflatpageoravalidurl` 会重定向到 `/notaflatpageoravalidurl/`，然后会引发 404 错误。现在请求 `/notaflatpageoravalidurl` 将立即引发 404 错误。

此外，平面页面返回的重定向现在是永久性的（使用 301 状态代码），以与 [`CommonMiddleware`](/zh-hans/5.2/ref/middleware/#django.middleware.common.CommonMiddleware) 的行为一致。

### [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) 和 [`time`](https://docs.python.org/3/library/datetime.html#datetime.time) 的序列化

作为时区支持的结果，并根据 ECMA-262 规范，我们对 JSON 序列化器进行了更改：

- 它包括了具有时区感知的 datetime 对象的时区。对于具有时区感知的 time 对象，它会引发一个异常。
- 它包括了 datetime 和 time 对象的毫秒数。由于 Python 存储微秒（6 位数字）而 JSON 仅支持毫秒（3 位数字），因此仍然存在一些精度损失。然而，这总比完全丢弃微秒要好。

我们更改了 XML 序列化器以使用 ISO8601 格式来表示日期时间。使用字母 `T` 来分隔日期部分和时间部分，而不是使用空格。时区信息以 `[+-]HH:MM` 格式包含在内。

尽管序列化器在创建固件时现在使用这些新格式，但它们仍然可以加载使用旧格式的固件。

### `supports_timezone` 对于 SQLite 现在更改为 `False`。

数据库特性 `supports_timezone` 以前对于 SQLite 是 `True`。确实，如果您保存了一个带有时区信息的 datetime 对象，SQLite 会存储一个包含 UTC 偏移的字符串。然而，在从数据库加载值时会忽略此偏移量，这可能会导致数据损坏。

在时区支持的背景下，此标志已更改为 `False`，并且在 SQLite 中现在以不带时区信息的方式存储日期时间。当 [`USE_TZ`](/zh-hans/5.2/ref/settings/#std-setting-USE_TZ) 为 `False` 时，如果尝试保存一个带有时区信息的 datetime 对象，Django 将引发异常。

### `MySQLdb` 特定的异常

MySQL 后端在历史上在查询触发异常时引发了 `MySQLdb.OperationalError`。我们已经修复了这个 bug，现在我们会引发 [`django.db.DatabaseError`](/zh-hans/5.2/ref/exceptions/#django.db.DatabaseError)。如果您在测试时使用了 `MySQLdb.OperationalError`，您需要更新您的 `except` 子句。

### 数据库连接的线程局部性

`DatabaseWrapper` 对象（即由 `django.db.connection` 和 `django.db.connections["some_alias"]` 引用的连接对象）以前是线程局部的。现在它们是全局对象，可以在多个线程之间共享。尽管单个连接对象现在是全局的，但引用这些对象的 `django.db.connections` 字典仍然是线程局部的。因此，如果您只是使用 ORM 或 `DatabaseWrapper.cursor()`，那么行为仍然与以前相同。但请注意，`django.db.connection` 现在不再直接引用默认的 `DatabaseWrapper` 对象，而是代理访问该对象的属性。如果您需要访问实际的 `DatabaseWrapper` 对象，请改用 `django.db.connections[DEFAULT_DB_ALIAS]`。

作为这个改变的一部分，现在所有底层的 SQLite 连接都已经启用了潜在的线程共享（通过将 `check_same_thread=False` 属性传递给 `pysqlite`）。然而，`DatabaseWrapper` 默认情况下仍然保留以前的行为，通过禁用线程共享，因此这不会影响任何纯粹依赖 ORM 或 `DatabaseWrapper.cursor()` 的现有代码。

最后，尽管现在可以在线程之间传递连接，但 Django 并未尝试同步访问底层后端。并发行为由底层后端实现定义。请查阅它们的文档以获取详细信息。

### `COMMENTS_BANNED_USERS_GROUP` 配置

Django 的评论历史上支持排除特殊用户组的评论，但我们从未正确记录此功能，并且没有在应用程序的其他部分（如模板标签）中执行排除。为了解决这个问题，我们从 feed 类中删除了代码。

如果您依赖此功能并希望恢复旧的行为，可以使用自定义评论模型管理器来排除用户组，如下所示：

```
from django.conf import settings
from django.contrib.comments.managers import CommentManager

class BanningCommentManager(CommentManager):
    def get_query_set(self):
        qs = super().get_query_set()
        if getattr(settings, "COMMENTS_BANNED_USERS_GROUP", None):
            where = [
                "user_id NOT IN (SELECT user_id FROM auth_user_groups WHERE group_id = %s)"
            ]
            params = [settings.COMMENTS_BANNED_USERS_GROUP]
            qs = qs.extra(where=where, params=params)
        return qs
```

请将此模型管理器保存在您的自定义评论应用中（例如，在 `my_comments_app/managers.py` 中），然后将其添加到您的自定义评论应用模型中：

```
from django.db import models
from django.contrib.comments.models import Comment

from my_comments_app.managers import BanningCommentManager

class CommentWithTitle(Comment):
    title = models.CharField(max_length=300)

    objects = BanningCommentManager()
```

### `IGNORABLE_404_STARTS` 和 `IGNORABLE_404_ENDS` 配置

在 Django 1.3 之前，可以通过在 `IGNORABLE_404_STARTS` 添加前缀和在 `IGNORABLE_404_ENDS` 添加后缀来将某些 URL 排除在 Django 的 [404 错误报告](/zh-hans/5.2/howto/error-reporting/) 之外。

在 Django 1.4 中，这两个设置被 [`IGNORABLE_404_URLS`](/zh-hans/5.2/ref/settings/#std-setting-IGNORABLE_404_URLS) 取代，它是一个编译后的正则表达式列表。Django 不会为匹配其中任何一个的 URL 的 404 错误发送电子邮件。

此外，以前的设置具有一些相当任意的默认值：

```
IGNORABLE_404_STARTS = ("/cgi-bin/", "/_vti_bin", "/_vti_inf")
IGNORABLE_404_ENDS = (
    "mail.pl",
    "mailform.pl",
    "mail.cgi",
    "mailform.cgi",
    "favicon.ico",
    ".php",
)
```

Django 不负责决定您的网站是否有一个遗留的 `/cgi-bin/` 部分或一个 `favicon.ico`。因此，[`IGNORABLE_404_URLS`](/zh-hans/5.2/ref/settings/#std-setting-IGNORABLE_404_URLS)、`IGNORABLE_404_STARTS` 和 `IGNORABLE_404_ENDS` 的默认值现在都为空。

如果您已经定制了 `IGNORABLE_404_STARTS` 或 `IGNORABLE_404_ENDS`，或者希望保留旧的默认值，您应该在您的设置文件中添加以下行：

```
import re

IGNORABLE_404_URLS = (
    # for each <prefix> in IGNORABLE_404_STARTS
    re.compile(r"^<prefix>"),
    # for each <suffix> in IGNORABLE_404_ENDS
    re.compile(r"<suffix>$"),
)
```

不要忘记转义在正则表达式中具有特殊含义的字符，例如句点。

### CSRF 保护扩展到 PUT 和 DELETE 操作

以前，Django 的 [CSRF 保护](/zh-hans/5.2/ref/csrf/) 仅对 POST 请求提供保护。由于在 AJAX 应用中使用 PUT 和 DELETE 方法变得越来越常见，因此现在我们对所有未被 [**RFC 2616**](https://datatracker.ietf.org/doc/html/rfc2616.html) 定义为安全的方法提供保护 — 即，我们排除了 GET、HEAD、OPTIONS 和 TRACE，对其他一切进行保护。

如果您在 AJAX 应用中使用 PUT 或 DELETE 方法，请参阅有关使用 AJAX 和 CSRF 的 [说明](/zh-hans/5.2/howto/csrf/#csrf-ajax)。

### 密码重置视图现在接受 `subject_template_name`

`django.contrib.auth` 中的 `password_reset` 视图现在接受一个 `subject_template_name` 参数，该参数作为关键字参数传递给密码保存表单。如果您正在使用自定义密码重置表单与此视图一起使用，那么您需要确保您的表单的 `save()` 方法接受此关键字参数。

### `django.core.template_loaders`

自 2005 年以来，这是对 `django.template.loader` 的别名，由于过长的弃用期，我们已将其删除而不发出警告。如果您的代码仍然引用了它，请改用 `django.template.loader`。

### `django.db.models.fields.URLField.verify_exists`

由于无法解决的性能和安全问题，已删除了此功能。应删除任何现有的 `verify_exists` 用法。

### `django.core.files.storage.Storage.open`

基本 Storage 类的 `open` 方法曾经接受一个晦涩的参数 `mixin`，允许您动态更改返回的文件对象的基类。这已被移除。在极少数情况下，如果您依赖于 `mixin` 参数，您可以通过覆盖 `open` 方法轻松实现相同的效果，如下所示：

```
from django.core.files import File
from django.core.files.storage import FileSystemStorage

class Spam(File):
    """
    Spam, spam, spam, spam and spam.
    """

    def ham(self):
        return "eggs"

class SpamStorage(FileSystemStorage):
    """
    A custom file storage backend.
    """

    def open(self, name, mode="rb"):
        return Spam(open(self.path(name), mode))
```

### YAML 反序列化器现在使用 `yaml.safe_load`

`yaml.load` 能够构造任何 Python 对象，如果处理来自不受信任的源的 YAML 文档，可能触发任意代码执行。这个特性对于 Django 的 YAML 反序列化器并不必要，因为它的主要用途是加载由简单对象组成的 fixture。尽管 fixture 是可信数据，但 YAML 反序列化器现在使用 `yaml.safe_load` 来提供额外的安全性。

### 会话 cookie 现在默认情况下具有 `httponly` 标志

为了减少潜在的 XSS 攻击影响，会话 cookie 现在默认包含 `httponly` 属性。由于这个改变，许多浏览器中的 JavaScript 不再可以访问会话 cookie 数据，包括 `sessionid`。为了严格的向后兼容性，在您的设置文件中使用 `SESSION_COOKIE_HTTPONLY = False`。

### [`urlize`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-urlize) 过滤器不再对每个 URL 进行转义

当一个 URL 包含一个 `%xx` 序列，其中 `xx` 是两个十六进制数字时，[`urlize`](/zh-hans/5.2/ref/templates/builtins/#std-templatefilter-urlize) 现在假定该 URL 已经被转义，不会再次应用 URL 转义。这对于其未引用形式包含 `%xx` 序列的 URL 是不正确的，但这种情况在实际使用中非常罕见，因为它们也会混淆浏览器。

### `assertTemplateUsed` 和 `assertTemplateNotUsed` 现在作为上下文管理器可用

现在可以使用 [`assertTemplateUsed()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertTemplateUsed) 和 [`assertTemplateNotUsed()`](/zh-hans/5.2/topics/testing/tools/#django.test.SimpleTestCase.assertTemplateNotUsed) 来检查模板是否在代码块中被使用，并且它们可以作为上下文管理器使用：

```
with self.assertTemplateUsed("index.html"):
    render_to_string("index.html")
with self.assertTemplateNotUsed("base.html"):
    render_to_string("index.html")
```

更多信息请查看 [断言文档](/zh-hans/5.2/topics/testing/tools/#assertions)。

### 运行测试套件后的数据库连接

默认的测试运行器在测试执行后不再恢复数据库连接。这可以防止生产数据库暴露给可能仍在运行并尝试创建新连接的潜在线程。

如果您的代码依赖于在测试执行后创建到生产数据库的连接，那么您可以通过子类化 `DjangoTestRunner` 并重写其 `teardown_databases()` 方法来恢复以前的行为。

### [`manage.py help`](/zh-hans/5.2/ref/django-admin/#django-admin-help) 的输出

[`manage.py help`](/zh-hans/5.2/ref/django-admin/#django-admin-help) 现在按应用程序分组列出可用命令。如果你依赖于此命令的输出，例如进行解析，那么你需要更新你的代码。要在脚本中获取所有可用管理命令的列表，请改用 [`manage.py help --commands`](/zh-hans/5.2/ref/django-admin/#django-admin-help)。

### `extends` 模板标签

以前，[`extends`](/zh-hans/5.2/ref/templates/builtins/#std-templatetag-extends) 标签使用了一种有缺陷的参数解析方法，这可能会导致它错误地将一个参数视为字符串文字，当它实际上不是字符串文字时。现在它使用 `parser.compile_filter`，与其他标签类似。

标签的内部不是官方稳定 API 的一部分，但为了充分披露，`ExtendsNode.__init__` 的定义已更改，这可能会破坏使用此类的自定义标签。

### 加载某些不完整的固件将不再工作

在 1.4 之前，当字段设置了 auto \_ now 或 auto \_ now \_ add 时，如果固件对象缺少特定的日期或日期时间值，则会插入一个默认值。这是本不应该工作的，而在 1.4 中，加载这样的不完整固件将会失败。因为固件是原始导入，所以它们应该明确指定所有字段值，而不考虑模型上的字段选项。

### 开发服务器多线程

开发服务器现在默认为多线程模式。使用 [`runserver --nothreading`](/zh-hans/5.2/ref/django-admin/#cmdoption-runserver-nothreading) 选项来禁用开发服务器中的多线程。

```shell
django-admin.py runserver --nothreading
```

### 在设置安全模式时，markdown 中的属性被禁用

在 Django 1.4 之前，无论过滤器的 safe 模式设置如何，属性都会包含在任何 markdown 输出中。在 Python-Markdown 库的版本 \> 2.1 中，添加了一个 enable\_attributes 选项。如果将 safe 参数传递给 markdown 过滤器，则同时设置 `safe_mode=True` 和 `enable_attributes=False` 选项。如果使用的是 Python-Markdown 库的版本小于 2.1，则会发出一个警告，指出输出不安全。

### FormMixin 的 get\_initial 返回特定实例的字典

在 Django 1.3 中，[`django.views.generic.edit.FormMixin`](/zh-hans/5.2/ref/class-based-views/mixins-editing/#django.views.generic.edit.FormMixin) 类的 `get_initial` 方法返回了类变量 `initial` 字典。现在已修复为返回该字典的副本，因此表单实例可以修改其初始数据，而不会影响类变量。

## 在 1.4 中被废弃的功能

### 调用 `cache_page` 装饰器的旧样式是：

已经弃用了一些旧的调用 [`cache_page()`](/zh-hans/5.2/topics/cache/#django.views.decorators.cache.cache_page) 的方式。请查阅文档以了解正确使用此装饰器的方法。

### 支持早于 8.2 版本的 PostgreSQL

Django 1.3 放弃了对早于 8.0 版本的 PostgreSQL 的支持，我们建议使用更新的版本，因为性能得到了改进，更重要的是，8.0 和 8.1 的上游支持期即将结束（2010 年 11 月）。

Django 1.4 进一步执行了该政策，并将 8.2 设置为官方支持的最低 PostgreSQL 版本。

### 请求异常现在总是被记录

当我们在 Django 1.3 中添加了 [日志支持](/zh-hans/5.2/topics/logging/) 时，管理后台错误电子邮件支持被移动到 [`django.utils.log.AdminEmailHandler`](/zh-hans/5.2/ref/logging/#django.utils.log.AdminEmailHandler)，并附加到 `'django.request'` 记录器上。为了保持错误电子邮件的已建立行为，只有在 [`DEBUG`](/zh-hans/5.2/ref/settings/#std-setting-DEBUG) 为 `False` 时才会调用 `'django.request'` 记录器。

为了增加请求的错误日志记录的灵活性，现在无论 [`DEBUG`](/zh-hans/5.2/ref/settings/#std-setting-DEBUG) 的值如何，都会调用 `'django.request'` 记录器，并且新项目的默认设置文件现在包括一个附加到 [`django.utils.log.AdminEmailHandler`](/zh-hans/5.2/ref/logging/#django.utils.log.AdminEmailHandler) 的独立过滤器，以防止在 `DEBUG` 模式下发送管理错误电子邮件：

```
LOGGING = {
    # ...
    "filters": {
        "require_debug_false": {
            "()": "django.utils.log.RequireDebugFalse",
        }
    },
    "handlers": {
        "mail_admins": {
            "level": "ERROR",
            "filters": ["require_debug_false"],
            "class": "django.utils.log.AdminEmailHandler",
        }
    },
}
```

如果您的项目在这个改变之前创建的，那么您的 [`LOGGING`](/zh-hans/5.2/ref/settings/#std-setting-LOGGING) 设置将不包括这个新的过滤器。为了保持向后兼容性，Django 将检测到您的 `'mail_admins'` 处理程序配置不包括 `'filters'` 部分，并将自动为您添加这个过滤器并发出一个即将弃用的警告。在 Django 1.5 中，这将成为一个弃用警告，在 Django 1.6 中，向后兼容性的 shim 将被完全移除。

在 `'mail_admins'` 处理程序下存在任何 `'filters'` 键将禁用这个向后兼容性 shim 和弃用警告。

### `django.conf.urls.defaults`

在 Django 1.3 之前，`include()`, `patterns()`, 和 `url()` 函数，以及 [`handler404`](/zh-hans/5.2/ref/urls/#django.conf.urls.handler404) 和 [`handler500`](/zh-hans/5.2/ref/urls/#django.conf.urls.handler500) 都位于一个名为 `django.conf.urls.defaults` 的模块中。

在 Django 1.4 中，它们位于 [`django.conf.urls`](/zh-hans/5.2/ref/urls/#module-django.conf.urls) 模块中。

### `django.contrib.databrowse`

Databrowse 已经有一段时间没有进行积极开发了，而且目前看来也没有改变的迹象。曾经有一个关于将 Databrowse 的功能整合到管理员界面的 [GSOC 项目](https://code.djangoproject.com/wiki/SummerOfCode2011#Integratedatabrowseintotheadmin) 的建议，但没有取得进展。虽然 Databrowse 已经被弃用，但仍然有可能通过增强 `django.contrib.admin` 来提供类似的功能集。

支持 Databrowse 的代码在与 Django 相同的条款下获得许可，因此个人或团队可以将其作为第三方项目采用。

### `django.core.management.setup_environ`

这个函数在旧的扁平 [`startproject`](/zh-hans/5.2/ref/django-admin/#django-admin-startproject) 布局下，为了使父级 "project" 目录可导入，临时修改了 `sys.path`。由于新的 `manage.py` 和默认项目布局不再需要路径的解决办法，因此此函数现在已经弃用。

这个函数从未被文档化或列为公共 API 的一部分，但它曾广泛推荐用于为用户脚本设置 "Django 环境"。这些用法应该通过设置 [`DJANGO_SETTINGS_MODULE`](/zh-hans/5.2/topics/settings/#envvar-DJANGO_SETTINGS_MODULE) 环境变量或使用 [`django.conf.settings.configure()`](/zh-hans/5.2/topics/settings/#django.conf.settings.configure) 来替代。

### `django.core.management.execute_manager`

这个函数以前被 `manage.py` 用于执行管理命令。它与 `django.core.management.execute_from_command_line` 完全相同，只是它首先调用了 `setup_environ`，而这个函数现在已经弃用。因此，`execute_manager` 也已经弃用；可以使用 `execute_from_command_line` 代替。虽然这两个函数都没有被文档化为公共 API 的一部分，但由于在现有的 `manage.py` 文件中的使用，需要一个弃用路径。

### 模板过滤器的 `is_safe` 和 `needs_autoescape` 属性：

两个标志，`is_safe` 和 `needs_autoescape`，定义了每个模板过滤器与 Django 的自动转义行为的交互方式。它们以前是过滤器函数的属性：

```
@register.filter
def noop(value):
    return value

noop.is_safe = True
```

然而，这种技术在与装饰器结合使用时会引发一些问题，特别是 [`@stringfilter`](/zh-hans/5.2/howto/custom-template-tags/#django.template.defaultfilters.stringfilter)。现在，这些标志是 [`@register.filter`](/zh-hans/5.2/howto/custom-template-tags/#django.template.Library.filter) 的关键字参数：

```
@register.filter(is_safe=True)
def noop(value):
    return value
```

请参阅 [过滤器和自动转义](/zh-hans/5.2/howto/custom-template-tags/#filters-auto-escaping) 以获取更多信息。

### 在 `INSTALLED_APPS` 中应用程序名称的通配符扩展

在 Django 1.3 之前，[`INSTALLED_APPS`](/zh-hans/5.2/ref/settings/#std-setting-INSTALLED_APPS) 中接受应用程序名称中的通配符，例如 `django.contrib.*`。扩展是通过基于文件系统的 `from <package> import *` 实现的。不幸的是，这种方法无法可靠地执行。

这种行为从未被记录。由于它不符合 Python 的风格，所以在 Django 1.4 中被移除了。如果您依赖于它，您必须编辑设置文件，明确列出所有应用程序。

### `HttpRequest.raw_post_data` 已经重命名为 `HttpRequest.body`

这个属性的命名有点混淆，虽然它被命名为 `HttpRequest.raw_post_data`，但它实际上提供了 HTTP 请求的主体。它已被重命名为 `HttpRequest.body`，而 `HttpRequest.raw_post_data` 已被弃用。

### `django.contrib.sitemaps` 中的 bug 修复可能会影响性能

在之前的版本中，用于站点地图类的 `Paginator` 对象被缓存，这可能导致站点地图过期。我们已经移除了缓存，所以现在每次请求站点地图都会创建一个新的 Paginator 对象，并调用 [`Sitemap`](/zh-hans/5.2/ref/contrib/sitemaps/#django.contrib.sitemaps.Sitemap) 子类的 [`items()`](/zh-hans/5.2/ref/contrib/sitemaps/#django.contrib.sitemaps.Sitemap.items) 方法。根据你的 `items()` 方法的具体操作，这可能会对性能产生负面影响。为了缓解性能影响，考虑在你的 `Sitemap` 子类中使用 [缓存框架](/zh-hans/5.2/topics/cache/)。

### 早于 2.1 版本的 Python-Markdown

早于 2.1 版本的 Python-Markdown 不支持禁用属性的选项。作为一个安全问题，在加速弃用时间表下，1.5 版本的 markup contrib 应用程序将不支持此库的早期版本。
