Django 3.1将于2020年8月发布!从3.1版本开始,Django将逐步原生支持异步,好比异步视图和中间件。html
Django 3.1只支持Python 3.六、3.七、3.8以及更高版本。python
下面重点介绍Django3.1的新特性:算法
在Django3.1中,要定义一个异步视图很简单,只需使用Python的async def
语法,Django会自动探测到它们,并在异步上下文中运行它们。异步视图有不少优势,好比可以在不使用Python线程的状况下为数百个链接提供服务,容许使用慢速流、长轮询和其余的响应类型等等。django
async def my_view(request): await asyncio.sleep(0.5) return HttpResponse('Hello, async world!')
不管你是运行在WSGI仍是ASGI模式,都支持全部异步特性。json
可是,在WSGI模式下使用异步代码可能会有性能损失,由于此时异步视图将在它们本身的一次性事件循环中运行,这意味着你虽然可使用异步特性,如并行的异步HTTP请求,但却没法得到异步堆栈的好处。缓存
咱们能够为所欲为地混合异步和同步的视图、中间件和测试,Django会确保咱们始终得到正确的执行上下文。可是,Django官方建议大多数时候依然使用同步视图,只有在真正有需求时使用异步视图,不过这彻底取决于你的选择,你能够任性的都使用异步视图。安全
Django3.1版本中的ORM、缓存层和其余执行长时间网络调用的代码还暂时不支持异步访问,会在后期发布的版本中增长对它们的支持。(个人官网https://www.liujiangblog.com...。)Django对异步的支持彻底向后兼容,对现有的同步代码没有速度限制,它不会对任何现有的Django项目产生明显的影响。网络
下面是另一个例子:session
import datetime from django.http import HttpResponse async def current_datetime(request): now = datetime.datetime.now() html = '<html><body><h1>欢迎访问刘江Django教程:https://www.liujiangblog.com</h1>It is now %s.</body></html>' % now return HttpResponse(html)
由于目前,Django尚未完成异步ORM的功能开发,为了在异步视图中使用ORM,须要将同步的代码转换为异步的代码,这就须要使用asgiref
库,这个库已经做为安装依赖随Django一块儿被安装。异步
核心是使用asgiref.sync
中的sync_to_async
方法。
使用方法有两种,第一种以函数调用的方式,注意括号的位置:
from asgiref.sync import sync_to_async results = sync_to_async(Blog.objects.get)(pk=123) #注意圆括号,千万不要写成results = sync_to_async(Blog.objects.get(pk=123))
第二种以装饰器的方式:
from asgiref.sync import sync_to_async @sync_to_async def get_blog(pk): return Blog.objects.select_related('author').get(pk=pk)
对等的,其实也有一个异步变同步的函数,用于在同步视图中包装异步调用:
from asgiref.sync import async_to_sync async def get_data(...): ... sync_get_data = async_to_sync(get_data) @async_to_sync async def get_other_data(...): ...
从Django3.1开始,中间件能够支持同步和异步请求的任何组合。若是Django不能同时支持这二者,它将调整请求以知足中间件的需求,但会下降性能。
默认状况下,Django假设你的中间件只能处理同步请求。要更改这个假设,请在中间件工厂函数或类上设置如下属性:
sync_capable
: 一个布尔值,指示中间件是否能够处理同步请求。默认为True。async_capable
: 一个布尔值,指示中间件是否能够处理异步请求。默认为False。若是中间件同时具备sync_capable=True
和async_capable=True
,那么Django将在不转换请求的状况下传递它。在这种状况下,可使用asyncio.iscoroutine function()
检查传递给您的get_response
对象是不是一个协程函数,从而肯定您的中间件是否会接收异步请求。
记住一个概念:同步和异步能力不是非左即右,互相矛盾的存在,能够共存!
那么怎么将中间件设置为同步的,或者异步的,或者同步加异步的呢?
在django.utils.decorators
模块中包含sync_only_middleware
、async_only_middleware
和sync_and_async_middleware
三个装饰器,用于帮咱们实现上面的功能。
中间件返回的可调用函数必须与get_response
方法的sync或async性质匹配。若是有异步get_response
响应,则必须返回一个协程函数(async def)。
若是中间件提供了process_view
、process_template_response
和process_exception
方法,则还应进行相应的调整以匹配同步/异步模式。若是你不这样作,Django会根据须要对它们进行单独的调整,并产生额外的性能惩罚。
下面是一个如何建立同时支持同步和异步功能的中间件的示例:
import asyncio from django.utils.decorators import sync_and_async_middleware @sync_and_async_middleware def simple_middleware(get_response): # One-time configuration and initialization goes here. if asyncio.iscoroutinefunction(get_response): async def middleware(request): # Do something here! response = await get_response(request) return response else: def middleware(request): # Do something here! response = get_response(request) return response return middleware
总的来讲,Django对同步/异步视图和同步/异步中间件之间的搭配组合有很好的适配能力,不会让咱们的项目运行不起来。只不过若是搭配不当,会致使性能损失。
从Django3.1开始,具有异步测试能力。
若是您只想测试异步视图的输出,标准测试客户端将在本身的异步循环中运行它们,你不须要作任何额外的工做。
可是,若是你想为Django项目编写彻底异步的测试,则须要考虑一些事情。
首先,测试方法必须是测试类上的async def
方法(以便为它们提供异步上下文)。Django将自动检测任何异步测试并包装它们,以便它们在本身的事件循环中运行。
其次,若是要在异步函数中进行测试,还必须使用异步测试客户端。也就是django.test.AsyncClient
或self.async_client
。
除了不支持follow
参数外,AsyncClient
的使用方法和同步的测试客户端基本相同,但全部发出请求的方法都必须使用await
语法:
async def test_my_thing(self): response = await self.async_client.get('/some-url/') self.assertEqual(response.status_code, 200)
Django3.1新增了 models.JSONField
和forms.JSONField
两种新的模型字段类型,用于保存JSON编码的数据。
MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL和SQLite 3.9.0+都支持JSONField。
JSONField能够自定义编码器和解码器,这从它的定义上就能够看出来:
class JSONField(encoder=None, decoder=None, **options)
JSONField.encoder
可选参数。用于对诸如datetime.datetime
或者UUID
之类的标准JSON序列化不了的数据指定自定义的编码器。它必须是json.JSONEncoder
的子类,好比 DjangoJSONEncoder
JSONField.decoder
可选参数。用于解码咱们自定义的编码数据。必须是 json.JSONDecoder
的子类。
若是你为JSONField字段提供了一个default默认值,它的值必须是一个不可变的类型。
对于forms.JSONField
,除了一样能够自定义编码器和解码器,还有一些表单特有的性质:
Textarea
''
(空字符串)required
, invalid
下面例举一些相对较小的新功能。其中最主要的是,Django3.1开始使用pathlib.Path
来替代传统的os.path了,建议你们仍是尽快更新知识,迁移到pathlib.Path
上来
django.contrib.admin
django.contrib.admin.EmptyFieldListFilter
XRegExp
升级到3.2.0django.contrib.auth
PASSWORD_RESET_TIMEOUT
配置项,用于替代4.0中将废弃的 PASSWORD_RESET_TIMEOUT_DAYS
AbstractBaseUser.get_session_auth_hash()
将使用SHA-256哈希算法django.contrib.humanize
intword
将支持负整数django.contrib.sessions
SESSION_COOKIE_SAMESITE
如今能够接收 'None'
(字符串)django.contrib.staticfiles
STATICFILES_DIRS
设置项开始支持 pathlib.Path
FileSystemStorage.save()
方法支持 pathlib.Path
FileField
和ImageField
如今支持可调用的参数用于保存数据。这让你能在运行时动态选择不一样的存储位置。__init__.py
文件的目录中加载了PositiveBigIntegerField
字段类型,相似 PositiveIntegerField
,从 0
到9223372036854775807
都是安全的。on_delete
参数,如今能够接收一个RESTRICT
值,用于模拟SQL语言中的 ON DELETE RESTRICT
约束行为。