Django 1.11 版本发行说明

2017 年 4 月 4 日

欢迎来到 Django 1.11 版本!

这些发布说明涵盖了 新功能,以及一些 不兼容变更,当您从 Django 1.10 或更早版本升级时,您需要注意。我们已经 开始了一些功能的弃用过程

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

Django 1.11 被指定为 长期支持版本。它将在发布后至少三年内接收安全更新。对于之前的 LTS 版本 Django 1.8,支持将于 2018 年 4 月结束。

Python 兼容性

Django 1.11 需要 Python 2.7、3.4、3.5、3.6 或 3.7(截止到 1.11.17 版本)。我们* 强烈建议* 并且只正式支持每个系列的最新版本。

Django 1.11.x 系列是支持 Python 2 的最后一个版本。下一个主要版本,Django 2.0,将仅支持 Python 3.4+。

弃用警告默认不再大声发出

与旧版本的 Django 不同,Django 自身的弃用警告默认不再显示。这与 Python 的默认行为一致。

此更改允许第三方应用在不添加用于避免弃用警告的代码的情况下同时支持 Django 1.11 LTS 和 Django 1.8 LTS 。

在发布 Django 2.0 后,我们建议第三方应用的作者停止支持所有在 1.11 之前的 Django 版本。在那时,您应该能够使用 python -Wd 运行您包的测试,以确保弃用警告出现。在修复弃用警告后,您的应用应该与 Django 2.0 兼容。

Django 1.11 新特性

基于类的模型索引

新的 django.db.models.indexes 模块包含了用于简化创建数据库索引的类。索引可以通过在模型中使用 Meta.indexes 选项来添加。

Index 类创建一个 b-tree 索引,就像您在模型字段上使用 db_index 或在模型的 Meta 类上使用 index_together 一样。它可以被子类化以支持不同的索引类型,比如 GinIndex。它还允许定义索引列的顺序(ASC/DESC)。

基于模板的小部件渲染

为了方便定制小部件,现在表单小部件的渲染是使用模板系统而不是在 Python 中进行的。请参阅 表单渲染 API

你可能需要调整你编写的任何自定义小部件,以适应一些 不兼容变更

Subquery 表达式

新的 SubqueryExists 数据库表达式允许创建明确的子查询。子查询可以使用 OuterRef 类引用来自外部查询集的字段。

次要特性

django.contrib.admin

django.contrib.auth

  • PBKDF2 密码哈希器的默认迭代次数增加了 20 %。
  • LoginViewLogoutView 基于类的视图替代了已弃用的 login()logout() 基于函数的视图。
  • PasswordChangeViewPasswordChangeDoneViewPasswordResetViewPasswordResetDoneViewPasswordResetConfirmViewPasswordResetCompleteView 基于类的视图替代了已弃用的 password_change(), password_change_done(), password_reset(), password_reset_done(), password_reset_confirm(), 和 password_reset_complete() 基于函数的视图。
  • PasswordResetConfirmView 的新属性 post_reset_login 允许在成功重置密码后自动登录用户。如果配置了多个 AUTHENTICATION_BACKENDS,可以使用 post_reset_login_backend 属性选择要使用的后端。
  • 为了避免通过 HTTP Referer 标头泄露密码重置令牌的可能性(例如,如果重置页面包含对托管在另一个域上的 CSS 或 JavaScript 的引用),PasswordResetConfirmView (但不是已弃用的 password_reset_confirm() 基于函数的视图)将令牌存储在会话中,并重定向到自身,以向用户呈现不带令牌的 URL 的密码更改表单。
  • update_session_auth_hash() 现在会旋转会话密钥,以允许密码更改来使被窃取的会话 Cookie 失效。
  • LoginViewLogoutView 的新属性 success_url_allowed_hosts 允许指定一组安全的主机,用于在登录和注销后进行重定向。
  • 已添加密码验证器的 help_textUserCreationForm
  • HttpRequest 现在传递给 authenticate(),如果身份验证后端接受 request 参数,则它将传递给身份验证后端。
  • user_login_failed() 信号现在接收一个 request 参数。
  • PasswordResetForm 支持自定义用户模型,该模型使用名称不是 'email' 的电子邮件字段。将 CustomUser.EMAIL_FIELD 设置为字段的名称。
  • get_user_model() 现在可以在导入时调用,即使在定义模型的模块中也可以。

django.contrib.contenttypes

  • remove_stale_contenttypes 命令中,当检测到陈旧的内容类型时,现在会列出一系列相关对象,如 auth.Permission,这些对象也将被删除。之前,只列出了内容类型(而且此提示是在 migrate 之后,而不是在一个单独的命令中)。

django.contrib.gis

  • 新的 GEOSGeometry.from_gml()OGRGeometry.from_gml() 方法允许从 GML 创建几何图形。
  • 在 SpatiaLite 上新增了对 dwithin 查询的支持。
  • Area 函数、Distance 函数以及距离查询现在在 SpatiaLite 上支持大地坐标。
  • 基于 OpenLayers 的表单小部件现在使用来自 https://cdnjs.cloudflare.comOpenLayers.js,这比旧的 https://openlayers.org/ 源更适合生产使用。它们还更新为使用 OpenLayers 3。
  • PostGIS 迁移现在可以改变字段尺寸。
  • 现在可以在创建 GDALRaster 对象时传递 sizeshapeoffset 参数。
  • 新增了对 IsValid 函数、MakeValid 函数以及 isvalid 查询的 SpatiaLite 支持。
  • 新增了对 Oracle 数据库的支持,包括 AsGML 函数、BoundingCircle 函数、IsValid 函数以及 isvalid 查询。

django.contrib.postgres

  • StringAgg 的新参数 distinct 决定了连接的值是否要去重。
  • 新的 GinIndexBrinIndex 类允许在数据库中创建 GINBRIN 索引。
  • django.contrib.postgres.fields.JSONField 接受一个新的参数 encoder,用于指定自定义类以编码不受标准编码器支持的数据类型。
  • 新的 CIText 混合类和 CITextExtension 迁移操作允许在 PostgreSQL 中使用 citext 扩展来进行不区分大小写的查找。提供了三个字段:CICharFieldCIEmailFieldCITextField
  • 新的 JSONBAgg 允许将值聚合为 JSON 数组。
  • HStoreField (模型字段)和 HStoreField (表单字段)允许存储空值。

缓存

  • Memcached 后端现在将 OPTIONS 的内容作为关键字参数传递给客户端构造函数,允许更高级的客户端行为控制。请参阅 cache arguments 文档以获取示例。
  • Memcached 后端现在允许在 LOCATION 中定义多个服务器,使用逗号分隔的字符串,以方便处理使用这种字符串的环境变量的第三方服务。

CSRF

  • 新增了 CSRF_USE_SESSIONS 设置,允许将 CSRF 令牌存储在用户的会话中,而不是在 cookie 中。

数据库后端

  • 在 PostgreSQL 9.5+ 和 Oracle 上,新增了 skip_locked 参数,用于执行带有 FOR UPDATE SKIP LOCKED 的查询,可通过 QuerySet.select_for_update() 使用。
  • 新增了 TEST[‘TEMPLATE’] 设置,允许 PostgreSQL 用户指定用于创建测试数据库的模板。
  • QuerySet.iterator() 现在在 PostgreSQL 上使用 server-side cursors。这个功能将一些用于保存查询结果的工作内存负载转移到数据库,可能会增加数据库的内存使用量。
  • 新增了对在 OPTIONS 中使用 'isolation_level' 选项的 MySQL 支持,允许指定 事务隔离级别。为了避免可能的数据丢失,建议从 MySQL 的默认级别 repeatable read 切换到 read committed。
  • 新增了对 cx_Oracle 5.3 的支持。

电子邮件

  • 新增了 EMAIL_USE_LOCALTIME 设置,允许将 SMTP 日期标头发送到本地时区,而不是 UTC。
  • EmailMessage.attach()attach_file() 现在在为 text/* 附件指定无法解码为 UTF-8 的二进制内容时,会回退到 MIME 类型 application/octet-stream

文件存储

  • 为了能够被 io.TextIOWrapper 包装,File 现在具有 readable()writable()seekable() 方法。

表单

国际化

  • 数字格式化和 NUMBER_GROUPING 设置支持非均匀的数字分组。

管理命令

迁移

  • 新增了对 uuid.UUID 对象的序列化支持。

模型

请求和响应

序列化

  • 新的 django.core.serializers.base.Serializer.stream_class 属性允许子类自定义默认流。
  • 可以通过向 serializers.serialize() 函数传递一个 cls 关键字参数来自定义 JSON 序列化器 使用的编码器。
  • DjangoJSONEncoder 现在可以序列化 timedelta 对象(被 DurationField 使用)。

模板

  • 现在可以将 mark_safe() 用作装饰器。
  • Jinja2 模板后端现在支持通过在 OPTIONS 中设置 'context_processors' 选项来配置上下文处理器。
  • regroup 标签现在返回 namedtuple 而不是字典,因此你可以在循环中直接解包组对象,例如 {% for grouper, list in regrouped %}
  • 新增了 resetcycle 模板标签,允许重置 cycle 模板标签的序列。
  • 现在可以为特定的 filesystem.Loader 指定特定的目录。

测试

验证器

1.11 中的向后不兼容更改

django.contrib.gis

  • 为了简化代码库并且因为现在安装起来更容易(相对于最初发布 contrib.gis 时的情况),现在在 GeoDjango 中需要 GDAL 作为依赖。在旧版本中,它只对 SQLite 有要求。
  • contrib.gis.maps 已被移除,因为它与已退役的 Google Maps API 版本进行交互,似乎没有维护。如果您正在使用它,请 告诉我们
  • GEOSGeometry 的等号运算符现在也会比较 SRID。
  • 基于 OpenLayers 的表单小部件现在使用 OpenLayers 3,同时更新了 gis/openlayers.htmlgis/openlayers-osm.html 模板。如果您对这些小部件进行子类化或扩展模板,请检查您的项目。此外,新的小部件与旧的小部件有一些不同。不再使用小部件中的工具栏,而是点击以绘制,点击并拖动以移动地图,以及点击并拖动一个点/顶点/角来移动它。
  • 不再支持 SpatiaLite < 4.0 。
  • 不再支持 GDAL 1.7 和 1.8 。
  • contrib.gis.forms.widgets 中的小部件和管理员的 OpenLayersWidget 现在使用 表单渲染 API 而不是 loader.render_to_string()。如果您使用自定义小部件模板,您需要确保您的表单渲染器可以找到它。例如,您可以使用 TemplatesSetting 渲染器。

django.contrib.staticfiles

  • 当使用散列的静态文件存储时,如果存在引用循环(例如,'foo.css' 引用 'bar.css',而 'bar.css' 又引用 'foo.css'),或者如果引用其他文件的文件链过深,无法在多次传递中解析,那么 collectstatic 在后处理期间可能会失败。在后一种情况下,可以通过 ManifestStaticFilesStorage.max_post_process_passes 增加传递次数。
  • 当使用 ManifestStaticFilesStorage 时,运行时未在清单中找到的静态文件现在会引发 ValueError,而不是返回不变的路径。您可以通过将 ManifestStaticFilesStorage.manifest_strict 设置为 False 来恢复到旧的行为。

数据库后端 API

本节介绍了第三方数据库后端可能需要的更改。

  • 新增了 DatabaseOperations.time_trunc_sql() 方法,以支持 TimeField 截断。它接受一个 lookup_typefield_name 参数,并返回将给定时间字段 field_name 截断为只具有给定精度的时间对象的适当 SQL。lookup_type 参数可以是 'hour''minute''second'
  • 新增了 DatabaseOperations.datetime_cast_time_sql() 方法,以支持 time 查询。它接受一个 field_nametzname 参数,并返回将日期时间值强制转换为时间值所需的 SQL。
  • 要启用 FOR UPDATE SKIP LOCKED 支持,请设置 DatabaseFeatures.has_select_for_update_skip_locked = True
  • 新的 DatabaseFeatures.supports_index_column_ordering 属性指定数据库是否允许在索引中定义列的排序。默认值为 True,而 DatabaseIntrospection.get_constraints() 方法应在每个返回的字典中包含一个 'orders' 键,该键包含一个列表,其中包含与索引中每列的排序对应的 'ASC' 和/或 'DESC' 值。
  • inspectdb 不再调用已弃用的 DatabaseIntrospection.get_indexes() 方法。自定义数据库后端应确保 DatabaseIntrospection.get_constraints() 返回所有类型的索引。
  • ignores_quoted_identifier_case 功能的名称更改为 ignores_table_name_case,以更准确地反映它的使用方式。
  • 新增了 name 关键字参数到 DatabaseWrapper.create_cursor(self, name=None) 方法,以允许在支持的后端上使用服务器端游标。

不再支持 PostgreSQL 9.2 和 PostGIS 2.0 。

PostgreSQL 9.2 的上游支持将于 2017 年 9 月结束。因此,Django 1.11 将 PostgreSQL 9.3 设为其官方支持的最低版本。

由于 PostgreSQL 9.2 是支持 PostGIS 2.0 的最后一个版本,因此也取消了对 PostGIS 2.0 的支持。

此外,支持的最低 psycopg2 版本从 2.4.5 提高到 2.5.4 。

LiveServerTestCase 现在绑定到零端口

与其采用端口范围并迭代查找空闲端口,LiveServerTestCase 现在绑定到零端口,并依赖操作系统分配空闲端口。不再使用 DJANGO_LIVE_TEST_SERVER_ADDRESS 环境变量,也不再使用 manage.py test --liveserver 选项。

如果需要将 LiveServerTestCase 绑定到特定端口,可以使用 Django 1.11.2 中新增的 port 属性。

django.contrib.authi18n 视图中加强了对不安全的重定向的保护。

LoginViewLogoutView (以及已弃用的函数式等效版本)和 set_language() 在应用程序运行在 HTTPS 上时,会保护用户免受被重定向到非 HTTPS 的 next URL 的影响。

QuerySet.get_or_create()update_or_create() 现在会验证参数。

为了防止拼写错误默默通过,get_or_create()update_or_create() 检查它们的参数是否是模型字段。这只会在一个方面引入向后不兼容,可能会暴露出项目中的错误。

pytz 现在是必需的依赖项,不再支持将 settings.TIME_ZONE = None

为了简化 Django 的时区处理,pytz 现在是必需的依赖项,它会自动与 Django 一起安装。

不再支持 settings.TIME_ZONE = None,因为这种行为通常不常用且可疑的有用性。如果希望根据系统时区自动检测时区,可以使用 tzlocal

  1. from tzlocal import get_localzone
  2. TIME_ZONE = get_localzone().zone

这与 settings.TIME_ZONE = None 类似,但它还设置了 os.environ['TZ']。如果存在情况下,您发现无法适应设置 TIME_ZONE 的代码,请通过 告诉我们

管理模板中的 HTML 更改

<p class="help"> 被替换为 <div> 标签,以允许在帮助文本中包含列表。

只读字段现在被包装在 <div class="readonly">...</div> 中,而不是 <p>...</p>,以允许字段内容包含任何类型的 HTML。

由于引入基于模板的小部件渲染,发生了一些更改。

移除了 django.forms.widgets 中一些未记录的类:

  • SubWidget
  • RendererMixin, ChoiceFieldRenderer, RadioFieldRenderer, CheckboxFieldRenderer
  • ChoiceInput, RadioChoiceInput, CheckboxChoiceInput

移除了未记录的 Select.render_option() 方法。

移除了 Widget.format_output() 方法。请使用自定义小部件模板替代。

如果 settings.USE_L10N=True,现在某些小部件的值,如 <select> 选项,将进行本地化。您可以通过使用 localize 模板标签关闭本地化,恢复到旧的行为,使用自定义小部件模板。

django.template.backends.django.Template.render() 禁止非字典上下文。

为了与多个模板引擎兼容,django.template.backends.django.Template.render() (从高级模板加载器 API(如 loader.get_template())返回)必须接收一个上下文字典,而不是 ContextRequestContext。如果您之前传递了这两个类中的任何一个,请改为传递一个字典 - 这样做是向后兼容旧版本的 Django。

迁移操作中的模型状态更改

为了提高应用迁移的速度,延迟了相关模型的渲染,直到需要它们的操作(例如 RunPython)。如果您有一个自定义操作,需要在 database_forwards()database_backwards()from_state 参数中使用模型类或模型实例,您必须使用 clear_delayed_apps_cache() 方法来渲染模型状态,如 编写自己的迁移操作 中所述。

PostgreSQL 上的服务器端游标

QuerySet.iterator() 使用服务器端游标在 PostgreSQL 上可能会阻止在事务池模式下使用 PgBouncer 运行 Django。要重新允许这样做,可以在 DATABASES 中使用 DISABLE_SERVER_SIDE_CURSORS 设置(在 Django 1.11.1 中添加)。

有关更多讨论,请参阅 事务池和服务器端游标

杂项

  • 如果在 feed 中没有任何项目具有 pubdateupdateddate 属性,那么 SyndicationFeed.latest_post_date() 现在会返回当前的 UTC 日期/时间,而不是一个没有任何时区信息的 datetime。

  • CSRF 失败现在会被记录到 django.security.csrf 日志器,而不是 django.request

  • 运行测试时,不再禁用 ALLOWED_HOSTS 验证。如果您的应用程序包括具有自定义主机名的测试,您必须将这些主机名包含在 ALLOWED_HOSTS 中。请参阅 测试与多主机名

  • ModelAdmin.list_display 中使用外键的 id(例如 'field_id')会显示相关对象的 ID。如果要恢复到对象的字符串表示的旧行为,请移除 _id 后缀。

  • 在模型表单中,具有 null=TrueCharField 现在会为空白值保存 NULL,而不是空字符串。

  • 在 Oracle 上,Model.validate_unique() 不再检查空字符串的唯一性,因为数据库会将该值解释为 NULL

  • 如果您子类化了 AbstractUser 并覆盖了 clean() 方法,请确保它调用了 super()。新的 AbstractUser.clean() 方法中会调用 BaseUserManager.normalize_email(),以便在模型表单验证等情况下应用标准化。

  • EmailFieldURLField 不再接受 strip 关键字参数。移除它,因为在旧版本的 Django 中它没有任何效果,这些字段总是会去除空格。

  • 表单小部件渲染的 checkedselected 属性现在使用 HTML5 布尔语法,而不再使用 XHTML 的 checked='checked'selected='selected'

  • RelatedManager.add()remove()clear()set() 现在会清除 prefetch_related() 缓存。

  • 为防止可能丢失的保存设置,如果在调用 teardown_test_environment() 之前再次调用 setup_test_environment(),它现在会引发异常。

  • 未记录的 DateTimeAwareJSONEncoder 别名(对于在 Django 1.0 中更名的 DjangoJSONEncoder)已被移除。

  • 如果没有指定 OPTIONS[‘loaders’] 并且 OPTIONS[‘debug’]False (后者默认为 DEBUG 的值),则现在会启用 cached template loader。如果您有一些不是线程安全的 模板标签,这可能会导致不兼容。

  • 过去在运行 migrate 命令之后不再提示删除陈旧的内容类型。现在请使用新的 remove_stale_contenttypes 命令。

  • 管理员界面中的 IntegerField 控件现在使用 type="number" 而不是 type="text"

  • 现在,条件 HTTP 标头根据 RFC 7232 的条件请求规范进行解析和比较,而不是较旧的 RFC 2616 规范。

  • patch_response_headers() 不再添加 Last-Modified 标头。根据 RFC 7234#section-4.2.2,在提供明确的过期时间的其他缓存标头旁边,例如 ExpiresCache-Control,此标头是无用的。因此,UpdateCacheMiddlewareadd_never_cache_headers() 调用 patch_response_headers(),因此也受到此更改的影响。

  • 在管理模板中,<p class="help"> 被替换为 <div> 标签,以允许在帮助文本中包含列表。

  • ConditionalGetMiddleware 不再设置 Date 头,因为 web 服务器会设置该头。它也不再设置 Content-Length 头,因为现在由 CommonMiddleware 完成此操作。

    如果您有一个中间件在 MIDDLEWAREMIDDLEWARE_CLASSES 设置中出现在 CommonMiddleware 之前,并且修改响应的内容,那么您必须重新排列您的中间件,以确保在设置 Content-Length 后不会修改响应,或者让修改响应的中间件重置 Content-Length 头。

  • get_model()get_models() 现在在所有应用程序的模型加载之前调用时会引发 AppRegistryNotReady 异常。以前它们只需要目标应用程序的模型被加载,因此可能返回未完全设置其关系的模型。如果您需要 get_model() 的旧行为,请将 require_ready 参数设置为 False

  • 未使用的 BaseCommand.can_import_settings 属性已被删除。

  • 未记录的 django.utils.functional.lazy_property 已被移除。

  • 为了与非多部分请求保持一致,MultiPartParser.parse() 现在会使 request.POST 保持不可变性。如果你要修改那个 QueryDict,你现在必须先复制它,例如 request.POST.copy()

  • 对于 cx_Oracle 版本小于 5.2 的支持已被移除。

  • 对于 IPython 版本小于 1.0 的支持已从 shell 命令中移除。

  • 私有 API Widget.build_attrs() 的签名已从 extra_attrs=None, **kwargs 更改为 base_attrs, extra_attrs=None

  • 通过测试客户端上传到一个 ImageField 的类似文件的对象(例如 StringIOBytesIO)现在需要一个具有通过 validate_image_file_extension 验证器的值的 name 属性。请参阅 Client.post() 中的注意事项。

  • FileField 现在会移动文件而不是复制它所接收的文件。使用默认的文件上传设置,文件大小超过 FILE_UPLOAD_MAX_MEMORY_SIZE 的文件现在具有与临时文件相同的权限(通常是 0o600),而不是系统的标准掩码(通常是 0o644)。如果您需要不考虑文件大小都具有相同权限,请设置 FILE_UPLOAD_PERMISSIONS

在 1.11 中被废弃的功能

请使用 django.urls.reverse()。例如:

  1. from django.db import models
  2. class MyModel(models.Model):
  3. ...
  4. @models.permalink
  5. def url(self):
  6. return ("guitarist_detail", [self.slug])

变成:

  1. from django.db import models
  2. from django.urls import reverse
  3. class MyModel(models.Model):
  4. ...
  5. def url(self):
  6. return reverse("guitarist_detail", args=[self.slug])

杂项

  • contrib.auth 中的 login()logout() 基于函数的视图已被弃用,推荐使用新的基于类的视图 LoginViewLogoutView
  • contrib.auth.views.logout_then_login() 的未使用的 extra_context 参数已被弃用。
  • contrib.auth 中的 password_change(), password_change_done(), password_reset(), password_reset_done(), password_reset_confirm(), 和 password_reset_complete() 基于函数的视图已被弃用,推荐使用新的基于类的视图 PasswordChangeView, PasswordChangeDoneView, PasswordResetView, PasswordResetDoneView, PasswordResetConfirmView, 和 PasswordResetCompleteView
  • django.test.runner.setup_databases() 已移至 django.test.utils.setup_databases()。旧位置已被弃用。
  • django.utils.translation.string_concat() 已被弃用,推荐使用 django.utils.text.format_lazy()。可以通过 format_lazy('{}' * len(strings), *strings) 来替代 string_concat(*strings)
  • 对于 PyLibMCCache 缓存后端,将 pylibmc 行为设置作为 OPTIONS 的顶级属性传递已被弃用。请将它们设置在 OPTIONS 内的 behaviors 键下。
  • django.utils.http.is_safe_url()host 参数已被弃用,推荐使用新的 allowed_hosts 参数。
  • 在渲染 {% include %} 模板标签时抑制异常已被弃用,因为这种行为通常会比有帮助更令人困惑。在 Django 2.1 中,将会引发异常。
  • DatabaseIntrospection.get_indexes() 已被弃用,推荐使用 DatabaseIntrospection.get_constraints()
  • authenticate() 现在向身份验证后端的 authenticate() 方法传递一个 request 参数。不接受 request 作为第一个位置参数的方法将在 Django 2.1 中被移除。
  • USE_ETAGS 设置已被弃用,推荐使用 ConditionalGetMiddleware,它现在会在响应中添加 ETag 头,不受设置的影响。当弃用结束时,CommonMiddlewaredjango.utils.cache.patch_response_headers() 将不再设置 ETags。
  • Model._meta.has_auto_field 已被弃用,推荐检查 Model._meta.auto_field is not None
  • url() 中使用带有 iLmsu# 的正则表达式组已被弃用。唯一有用的组是 (?i) 用于不区分大小写的 URL,但是不区分大小写的 URL 并不是一个好的实践,因为它们会为搜索引擎创建多个条目,例如。一个替代方案可能是创建一个 handler404,它查找 URL 中的大写字符并重定向到相应的小写字符。
  • renderer 参数已添加到 Widget.render() 方法。不接受该参数的方法将在一个弃用期内继续工作。