Django 2.0 版本发行说明Link to this heading
2017 年 12 月 2 日
欢迎来到 Django 2.0 版本!
这些发布说明涵盖了 新特性,以及从 Django 1.11 或更早版本升级时需要注意的一些 不兼容的变更。我们已经 删除了一些已经达到了弃用周期末尾的功能,并且我们已经 开始了一些功能的弃用过程。
这个发布版本开始使用了 Django 的一种 松散形式的语义版本,但并没有出现与 2.0 版本发布相符的重大不兼容变更。升级应该与过去的功能发布相似的努力。
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Python 兼容性Link to this heading
Django 2.0 支持 Python 3.4、3.5、3.6 和 3.7。我们 强烈建议 并且只官方支持每个系列的最新版本。
Django 1.11.x 系列是支持 Python 2.7 版本的最后一个系列。
Django 2.0 将是最后一个支持 Python 3.4 的发布系列。如果您计划在 Django 2.0 的生命周期结束后(2019 年 4 月)继续使用 Python 3.4,请改用 Django 1.11 LTS(支持到 2020 年 4 月)代替。请注意,Python 3.4 的生命周期将于 2019 年 3 月结束。
对于较旧版本的 Django 的第三方库支持Link to this heading
在 Django 2.0 发布之后,我们建议第三方应用程序的作者停止支持 1.11 之前的所有 Django 版本。在那个时候,你应该能够使用 python -Wd 运行你包的测试,以便弃用警告会出现。在进行弃用警告修复后,你的应用程序应该与 Django 2.0 兼容。
Django 2.0 新特性Link to this heading
简化 URL 路由语法Link to this heading
The new django.urls.path() function allows a simpler, more readable URL
routing syntax. For example, this example from previous Django releases:
url(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
可以写成:
path("articles/<int:year>/", views.year_archive),
新版本语法支持对 URL 参数的强制类型转换。在这个例子中,视图将会以数字类型接收参数 year 而不是以字符串类型。而且 URLs 的匹配限制也减少了。例如,因为参数 year 并没有像正则表达式中那样明确限制为四位数,year 为 10000 也会匹配成功。
旧版本中的 django.conf.urls.url() 函数现在可以在 django.urls.re_path() 中获取。前者依然保留,向后兼容,并没有立即弃用。旧版本中的 django.conf.urls.include() 函数现在可以从 django.urls 中导入,这样你就可以在 URLconfs 中使用 from django.urls import include, path, re_path 。
重新编写的文档 URL调度器 涵盖了新的语法并且提供了更多的细节。
contrib.admin 针对移动设备的优化改进Link to this heading
新版本的 admin 可以响应和支持所有主流移动设备。较旧的浏览器可能会遇到不同程度的功能降低。
Window 表达式Link to this heading
次要特性Link to this heading
django.contrib.adminLink to this heading
新的
ModelAdmin.autocomplete_fields属性和ModelAdmin.get_autocomplete_fields()方法允许在ForeignKey和ManyToManyField上使用 Select2 搜索小部件。
django.contrib.authLink to this heading
PBKDF2 密码散列器的默认迭代计数从 36,000 增加到 100,000。
django.contrib.gisLink to this heading
增加了
AsGeoJSON函数、GeoHash函数、IsValid函数、isvalid查找、以及 distance lookups 对 MySQL 的支持。添加了 PostGIS 和 SpatiaLite 支持的两个函数
Azimuth和LineLocatePoint。现在所有从 GeoJSON 导入的
GEOSGeometry都设置了其 SRID。添加了
OSMWidget.default_zoom属性来自定义地图的默认缩放级别。允许使用
papsz_options将 driver-specific creation options 传递给GDALRaster对象。允许在 GDAL 的内部虚拟文件系统中创建
GDALRaster对象。现在可以将栅格数据从内存中的二进制数据 创建和转换。新的
GDALBand.color_interp()方法返回了该波段的颜色解释。
django.contrib.postgresLink to this heading
对于
ArrayAgg,新的distinct参数确定连接的值是否是不同的。新的
RandomUUID数据库函数返回版本 4 的 UUID。它需要使用 PostgreSQL 的pgcrypto扩展,可以通过新的CryptoExtension迁移操作来激活。django.contrib.postgres.indexes.GinIndex现在支持fastupdate和gin_pending_list_limit参数。新的
GistIndex类允许在数据库中创建GiST索引。新的BtreeGistExtension迁移操作安装了btree_gist扩展,以添加对不是内置的操作符类的支持。inspectdb现在可以内省JSONField和各种RangeField(必须将django.contrib.postgres添加到INSTALLED_APPS中)。
django.contrib.sitemapsLink to this heading
在
GenericSitemap构造函数中添加了protocol关键字参数。
缓存Link to this heading
cache.set_many()现在返回一个未能插入的键的列表。对于内置的后端,失败的插入只会发生在 memcached 上。
文件存储Link to this heading
File.open()可以作为上下文管理器使用,例如with file.open() as f:。
表单Link to this heading
对于
SplitDateTimeWidget和SplitHiddenDateTimeWidget,新的date_attrs和time_attrs参数允许指定不同的 HTML 属性用于DateInput和TimeInput(或隐藏)子部件。新的
Form.errors.get_json_data()方法返回适用于包含在 JSON 响应中的表单错误的字典。
通用视图Link to this heading
新属性
ContextMixin.extra_context允许在View.as_view()添加上下文。
管理命令Link to this heading
inspectdb现在将 MySQL 的无符号整数列翻译为PositiveIntegerField或PositiveSmallIntegerField。新的
makemessages --add-location选项控制.po文件中的注释格式。新的
diffsettings --output选项允许以统一的差异格式格式化输出。在 Oracle 上,
inspectdb现在可以内省AutoField,如果列被创建为标识列(identity column)。在 MySQL 上,
dbshell现在支持客户端端的 TLS 证书。
迁移Link to this heading
新的
squashmigrations --squashed-name选项允许命名合并后的迁移。
模型Link to this heading
新的
StrIndex数据库函数用于查找一个字符串在另一个字符串中的起始索引。在 Oracle 上,现在会将
AutoField和BigAutoField创建为 标识列。QuerySet.iterator()的新参数chunk_size控制在从数据库流式传输结果时由 Python 数据库客户端提取的行数。对于不支持服务器端游标的数据库,它控制 Django 从数据库适配器提取的结果数量。QuerySet.earliest()、QuerySet.latest()和Meta.get_latest_by现在允许按多个字段排序。新增了
ExtractQuarter函数,用于从DateField和DateTimeField中提取季度,并通过quarter查找公开。新增了
TruncQuarter函数,用于将DateField和DateTimeField截断到季度的第一天。为基于类的索引添加了
db_tablespace参数。如果数据库支持原生的持续时间字段(Oracle 和 PostgreSQL),
Extract现在可以与DurationField一起使用。Added the
ofargument toQuerySet.select_for_update(), supported on PostgreSQL and Oracle, to lock only rows from specific tables rather than all selected tables. It may be helpful particularly whenselect_for_update()is used in conjunction withselect_related().QuerySet.in_bulk()的新参数field_name允许根据任何唯一模型字段获取结果。CursorWrapper.callproc()now takes an optional dictionary of keyword parameters, if the backend supports this feature. Of Django's built-in backends, only Oracle supports it.内置聚合函数的新
filter参数允许在同一字段或关系上的多个聚合中 添加不同的条件。在
Meta.ordering中添加了对表达式的支持。QuerySet.values_list()的新参数named允许将结果作为命名元组获取。新的
FilteredRelation类允许在查询集中添加一个ON子句。
分页Link to this heading
添加了
Paginator.get_page(),以提供处理无效页码的文档化模式。
请求和响应Link to this heading
runserverWeb 服务器支持 HTTP 1.1。
模板Link to this heading
为了增加第三方应用程序中
Engine.get_default()的实用性,如果在TEMPLATES中配置了多个DjangoTemplates引擎,它现在将返回第一个引擎,而不是引发ImproperlyConfigured异常。现在自定义模板标签可以接受仅限关键字的参数。
测试Link to this heading
向
LiveServerTestCase添加了多线程支持。添加了允许自定义 Oracle 测试表空间参数的设置:
DATAFILE_SIZE、DATAFILE_TMP_SIZE、DATAFILE_EXTSIZE和DATAFILE_TMP_EXTSIZE。
验证器Link to this heading
新的
ProhibitNullCharactersValidator在CharField表单字段及其子类的输入中禁止使用空字符。空字符输入是由于漏洞扫描工具而观察到的。大多数数据库会悄悄地丢弃空字符,但是当尝试将空字符保存到 PostgreSQL 的 char/text 字段时,psycopg2 2.7+ 会引发异常。
2.0 版本的不向后兼容变更Link to this heading
在某些地方移除了对字节字符串的支持Link to this heading
为了支持原生的 Python 2 字符串,旧版本的 Django 必须同时接受字节字符串和 Unicode 字符串。现在 Python 2 的支持已被移除,字节字符串应该只出现在输入/输出边界(例如处理二进制字段或 HTTP 流)附近。您可能需要更新您的代码,以将字节字符串的使用限制到最低,因为 Django 不再在某些代码路径中接受字节字符串。Python 的 -b 选项可能有助于检测代码中的这种错误。
例如,现在 reverse() 在将接收到的 args 和 kwargs 放置在 URL 之前,使用 str() 而不是 force_text() 来强制转换它们。对于字节字符串,这会创建一个带有不希望的 b 前缀以及额外引号的字符串(str(b'foo') 是 "b'foo'")。为了适应这种变化,在将字节字符串传递给 reverse() 之前,请调用 decode()。
数据库后端 APILink to this heading
本节介绍了第三方数据库后端可能需要的更改。
现在,
DatabaseOperations.datetime_cast_date_sql()、datetime_cast_time_sql()、datetime_trunc_sql()、datetime_extract_sql()和date_interval_sql()方法仅返回执行操作的 SQL,而不再返回 SQL 和参数列表。第三方数据库后端应该添加一个名为
DatabaseWrapper.display_name的属性,该属性包含您的后端适用于的数据库名称。Django 可能会在各种消息中使用它,例如系统检查中。SchemaEditor._alter_column_type_sql()的第一个参数现在是model,而不再是table。SchemaEditor._create_index_name()的第一个参数现在是table_name,而不再是model。要启用
FOR UPDATE OF支持,请设置DatabaseFeatures.has_select_for_update_of = True。如果数据库要求OF的参数是列而不是表,请设置DatabaseFeatures.select_for_update_of_column = True。要启用对
Window表达式的支持,请将DatabaseFeatures.supports_over_clause设置为True。您可能需要自定义DatabaseOperations.window_start_rows_start_end()和/或window_start_range_start_end()方法。第三方数据库后端应该添加一个名为
DatabaseOperations.cast_char_field_without_max_length的属性,该属性指定在没有提供max_length参数的情况下,在Cast函数中将用于CharField的数据库数据类型。DatabaseCreation._clone_test_db()和get_test_db_clone_settings()的第一个参数现在是suffix,而不再是number``(如果您希望为了一致性而在您的后端中重命名签名)。``django.test现在也将这些值作为字符串而不是整数传递。第三方数据库后端应该基于
BaseDatabaseIntrospection中的存根添加一个名为DatabaseIntrospection.get_sequences()的方法。
不再支持 Oracle 11.2Link to this heading
Oracle 11.2 的上游支持将于 2020 年 12 月结束。 Django 1.11 将在 2020 年 4 月之前得到支持,几乎达到了这个日期。 Django 2.0 正式支持 Oracle 12.1 及更高版本。
默认的 MySQL 隔离级别为读已提交(read committed)Link to this heading
MySQL 的默认隔离级别,可重复读(repeatable read),在典型的 Django 使用中可能会导致数据丢失。为了防止这种情况并保持与其他数据库的一致性,现在默认的隔离级别是读提交(read committed)。如果需要,您可以使用 DATABASES 设置来 使用不同的隔离级别。
AbstractUser.last_name 的 max_length 增加到了 150。Link to this heading
包含了 django.contrib.auth.models.User.last_name 的迁移。如果您有一个从 AbstractUser 继承的自定义用户模型,您需要生成并应用一个数据库迁移来更新您的用户模型。
如果您想保留姓氏的 30 个字符限制,请使用自定义表单:
from django.contrib.auth.forms import UserChangeForm
class MyUserChangeForm(UserChangeForm):
last_name = forms.CharField(max_length=30, required=False)
如果你想在管理中编辑用户时保留这个限制,请将 UserAdmin.form 设置为使用这个表单:
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
在切片之后,禁止使用 QuerySet.reverse() 和 last()。Link to this heading
在切片后调用 QuerySet.reverse() 或 last() 会导致意外的结果,因为切片是在重新排序后应用的。现在已禁止这样使用,例如:
>>> Model.objects.all()[:2].reverse()
Traceback (most recent call last):
...
TypeError: Cannot reverse a query once a slice has been taken.
表单字段不再将可选参数作为位置参数接受Link to this heading
为了帮助防止由于表单字段参数顺序不正确而导致的运行时错误,内置表单字段的可选参数不再作为位置参数接受。例如:
forms.IntegerField(25, 10)
会引发异常,并且应该替换为:
forms.IntegerField(max_value=25, min_value=10)
call_command() 验证它接收到的选项Link to this heading
call_command() 现在验证被调用的命令的参数解析器是否定义了传递给 call_command() 的所有选项。
对于使用非 parser.add_argument() 创建的选项的自定义管理命令,请在命令上添加一个名为 stealth_options 的属性:
class MyCommand(BaseCommand):
stealth_options = ("option_name", ...)
索引不再接受位置参数Link to this heading
例子:
models.Index(["headline", "-pub_date"], "index_name")
会引发异常,并且应该替换为:
models.Index(fields=["headline", "-pub_date"], name="index_name")
现在在 SQLite 上启用了外键约束(Foreign key constraints)Link to this heading
如果尝试保存违反外键约束的现有模型实例,将会出现不兼容的后向变更(IntegrityError: FOREIGN KEY constraint failed)。
外键现在使用 DEFERRABLE INITIALLY DEFERRED 而不是 DEFERRABLE IMMEDIATE 来创建。因此,可能需要重新构建表以使用新的定义重新创建外键,特别是如果您使用了类似这样的模式:
from django.db import transaction
with transaction.atomic():
Book.objects.create(author_id=1)
Author.objects.create(id=1)
如果不将外键重新创建为 DEFERRED,那么由于现在强制执行外键约束,第一次的 create() 将会失败。
首先备份您的数据库!在升级到 Django 2.0 后,您可以使用类似以下脚本的方式重新构建表格:
from django.apps import apps
from django.db import connection
for app in apps.get_app_configs():
for model in app.get_models(include_auto_created=True):
if model._meta.managed and not (model._meta.proxy or model._meta.swapped):
for base in model.__bases__:
if hasattr(base, "_meta"):
base._meta.local_many_to_many = []
model._meta.local_many_to_many = []
with connection.schema_editor() as editor:
editor._remake_table(model)
这个脚本尚未经过广泛测试,并且需要根据不同情况进行调整,比如多个数据库的情况。欢迎贡献改进。
另外,由于 SQLite 的表更改限制,禁止在事务中对被其他模型引用的模型或字段执行 RenameModel 和 RenameField 操作。为了允许应用包含这些操作的迁移,您必须将 Migration.atomic 属性设置为 False。
杂项Link to this heading
SessionAuthenticationMiddleware类已被移除。自 Django 1.10 版本起,它不再提供任何功能,因为会话身份验证已无条件启用。默认的 HTTP 错误处理程序(
handler404等)现在是可调用函数,而不再是点分 Python 路径字符串。Django 更倾向于可调用引用,因为它们提供更好的性能和调试体验。RedirectView不再在pattern_name不存在时抑制NoReverseMatch。当
USE_L10N关闭时,FloatField和DecimalField现在在验证过程中会尊重DECIMAL_SEPARATOR和THOUSAND_SEPARATOR。例如,使用以下设置:USE_L10N = False USE_THOUSAND_SEPARATOR = True DECIMAL_SEPARATOR = "," THOUSAND_SEPARATOR = "."输入值
"1.345"现在被转换为1345,而不是1.345。AbstractBaseUser的子类不再需要实现get_short_name()和get_full_name()。(已删除引发NotImplementedError的基本实现。)如果实现了这些方法,django.contrib.admin将使用它们,但不再要求它们。使用这些方法的第三方应用程序可能希望采用类似的方法。FIRST_DAY_OF_WEEK和NUMBER_GROUPING格式设置现在在 JavaScript 和 JSON i18n 视图输出中保持为整数。assertNumQueries()现在忽略连接配置查询。以前,如果一个测试打开了一个新的数据库连接,那些查询可能会被包括在assertNumQueries()计数中。Oracle 测试表空间的默认大小从 20M 增加到 50M,自动扩展的默认大小从 10M 增加到 25M 。
为了提高从数据库流式传输大型结果集的性能,
QuerySet.iterator()现在一次获取 2000 行,而不是 100 行。可以使用chunk_size参数恢复旧的行为。例如:Book.objects.iterator(chunk_size=100)在
JavaScriptCatalog视图的packages参数中提供未知的包名称现在会引发ValueError,而不是默默通过。现在,默认的
Model.__str__()方法中会显示模型实例的主键,例如Question object (1)。现在,
makemigrations会检测到模型字段的limit_choices_to选项的更改。请将其添加到现有的迁移中,或接受为使用它的字段生成的自动生成的迁移。在 MySQL 上执行需要 自动空间转换 的查询现在会引发
NotImplementedError,而不再默默地使用未经转换的几何图形。移除了
django.core.exceptions.DjangoRuntimeWarning。它只在缓存后端中用作CacheKeyWarning继承RuntimeWarning的中间类。将
BaseExpression._output_field重命名为output_field。您可能需要更新自定义表达式。在旧版本中,表单和表单集通过连接两者的
Media来合并小部件的Media。现在,合并尝试 保持每个列表中元素的相对顺序。如果无法保持顺序,将发出MediaOrderConflictWarning警告。移除了
django.contrib.gis.gdal.OGRException。自 Django 1.8 起,它一直是GDALException的别名。不再支持 GEOS 3.3.x 版本。
选择
GeometryField的数据的方式已更改以提高性能,在原始 SQL 查询中,现在必须将这些字段包装在connection.ops.select中。请参阅 GIS 教程中的 原始查询注意事项 以获取示例。
在 2.0 中被废弃的功能Link to this heading
Field.from_db_value() 和 Expression.convert_value() 的 context 参数Link to this heading
Field.from_db_value() 和 Expression.convert_value() 的 context 参数未被使用,因为它始终是一个空字典。现在这两个方法的签名是:
(self, value, expression, connection)
替换成:
(self, value, expression, connection, context)
对于自定义字段和表达式的旧签名,将继续支持直到 Django 3.0 版本。
杂项Link to this heading
django.db.backends.postgresql_psycopg2模块已被弃用,推荐使用django.db.backends.postgresql。自 Django 1.9 起,它一直是一个别名。这仅影响直接从模块导入的代码。尽管如此,DATABASES设置仍然可以使用'django.db.backends.postgresql_psycopg2',但您可以使用 Django 1.9 中添加的'django.db.backends.postgresql'名称来简化它。django.shortcuts.render_to_response()已被弃用,推荐使用django.shortcuts.render()。render()接受与之前相同的参数,只是现在需要传递一个request参数。DEFAULT_CONTENT_TYPE设置已被弃用。它与第三方应用程序的兼容性不佳,并且自 HTML5 大多代替了 XHTML 后已过时。HttpRequest.xreadlines()已被弃用,建议改为迭代请求对象。QuerySet.earliest()和QuerySet.latest()中的field_name关键字参数已被弃用,推荐将字段名称作为参数传递。请使用.earliest('pub_date')而不是.earliest(field_name='pub_date')。
在 2.0 版本中移除的功能Link to this heading
这些功能已经完成了废弃周期,并在 Django 2.0 中被移除。
有关这些更改的详细信息,包括如何删除对这些特性的使用,请参阅 在 1.9 中被废弃的功能。
django.dispatch.signals.Signal.disconnect()中的weak参数已被移除。django.db.backends.base.BaseDatabaseOperations.check_aggregate_support()已被移除。django.forms.extras包已被移除。assignment_tag辅助函数已被移除。SimpleTestCase.assertsRedirects()中的host参数已被移除。兼容性层也被移除,该层允许在路径相同时将绝对 URL 视为与相对 URL 相等。Field.rel和Field.remote_field.to已被移除。在模型和迁移中,
ForeignKey和OneToOneField的on_delete参数现在是必需的。考虑合并迁移以减少需要更新的迁移数量。移除了
django.db.models.fields.add_lazy_relation()。启用时间区域支持时,不再在数据库后端不支持时间区域的情况下将感知的日期时间转换为 UTC 中的非感知值,当这样的值作为参数传递给 ORM 之外的 SQL 查询执行时(例如使用
cursor.execute())。django.contrib.auth.tests.utils.skipIfCustomUser()已被移除。GeoManager和GeoQuerySet类已被移除。django.contrib.gis.geoip模块已被移除。模板加载器的
supports_recursion检查已从以下地方移除:django.template.engine.Engine.find_template()django.template.loader_tags.ExtendsNode.find_template()django.template.loaders.base.Loader.supports_recursion()django.template.loaders.cached.Loader.supports_recursion()
已移除
load_template和load_template_sources模板加载器方法。模板加载器的
template_dirs参数已被移除:django.template.loaders.base.Loader.get_template()django.template.loaders.cached.Loader.cache_key()django.template.loaders.cached.Loader.get_template()django.template.loaders.cached.Loader.get_template_sources()django.template.loaders.filesystem.Loader.get_template_sources()
django.template.loaders.base.Loader.__call__()已被移除。不接受
exception参数的自定义错误视图的支持已被移除。django.utils.feedgenerator.Atom1Feed和django.utils.feedgenerator.RssFeed的mime_type属性已被移除。include()中的app_name参数已被移除。不再支持将一个包含
admin.site.urls的 3 元组作为include()的第一个参数。不再支持在没有应用程序命名空间的情况下设置 URL 实例命名空间。
Field._get_val_from_obj()已被移除。移除了
django.template.loaders.eggs.Loader。contrib.auth函数式视图的current_app参数已被移除。SimpleTestCase.assertRaisesMessage()中的callable_obj关键字参数已被移除。不再支持在
ModelAdmin方法上的allow_tags属性。SyndicationFeed.add_item()中的enclosure关键字参数已被移除。django.template.loader.LoaderOrigin和django.template.base.StringOrigin别名已被移除,对应的是django.template.base.Origin。
请参阅 在 1.10 中被废弃的功能 以获取有关这些更改的详细信息。
makemigrations --exit选项已被移除。不再支持直接对反向外键或多对多关系进行赋值。
django.contrib.gis.geos.GEOSGeometry的get_srid()和set_srid()方法已被移除。django.contrib.gis.geos.Point的get_x(),set_x(),get_y(),set_y(),get_z(), 和set_z()方法已被移除。django.contrib.gis.geos.Point的get_coords()和set_coords()方法已被移除。django.contrib.gis.geos.MultiPolygon的cascaded_union属性已被移除。django.utils.functional.allow_lazy()已被移除。shell --plain选项已被移除。django.core.urlresolvers模块已被移除,现在请使用其新位置django.urls。CommaSeparatedIntegerField已被移除,除了对历史迁移的支持外。模板
Context.has_key()方法已被移除。对于
django.core.files.storage.Storage.accessed_time(),created_time()和modified_time()方法的支持已被移除。当设置了
Meta.default_related_name时,不再支持使用模型名称进行查询查找。MySQL 中的
__search查找已被移除。移除了支持自定义相关管理器类但没有
_apply_rel_filters()方法的 shim。不再支持将
User.is_authenticated()和User.is_anonymous()作为方法使用,而不是属性。Model._meta.virtual_fields属性已被移除。Field.contribute_to_class()中的关键字参数virtual_only和Model._meta.add_field()中的virtual已被移除。javascript_catalog()和json_catalog()视图已被移除。django.contrib.gis.utils.precision_wkt()已被移除。在多表继承中,不再隐式将
OneToOneField提升为parent_link。不再支持
Widget._format_value()。FileField的方法get_directory_name()和get_filename()已被移除。mark_for_escaping()函数以及它使用的类:EscapeData、EscapeBytes、EscapeText、EscapeString和EscapeUnicode都已被移除。escape过滤器现在使用django.utils.html.conditional_escape()。Manager.use_for_related_fields已被移除。模型的
Manager继承遵循 MRO 继承规则。不再需要使用Meta.manager_inheritance_from_future来选择使用这种行为。不再支持使用
settings.MIDDLEWARE_CLASSES的老式中间件。