从Django 3.1开始,即几周前发布的最新版本,Django现在完全支持异步请求路径。这对于自Andrew Godwin的DEP 0009在2019年7月被Django技术委员会批准以来一直在等待的每个人来说都很兴奋。如果你有一个生产中的Django应用程序并希望添加异步支持,请继续阅读以了解这个版本的所有内容。
在DeepSource,我们正在努力在我们的Python分析器中添加更多的Django问题,这也将包括使用静态分析检测到的async特定错误风险和反模式。
对异步视图和中间件的支持
在Django 3.1中,异步功能现在支持整个请求-响应周期。这意味着你可以使用async 关键字来定义完全异步的视图:
async def get_cat_facts(request):
"""Return a random cat fact."""
async with aiohttp.ClientSession() as session:
async with session.get('https://catfact.ninja/fact') as resp:
data = await resp.json()
return data
最令人兴奋的是,异步支持是完全向后兼容的。这意味着你可以使用任何异步和同步视图的组合,而Django会保证执行总是在正确的执行环境中完成。因此,如果你想在不马上移植所有东西的情况下沾沾自喜,你可以直接翻转开关,只添加一个异步视图,而不会对现有的同步代码造成任何速度上的退步。
你也可以在你的中间件函数中使用async的优点:
def simple_middleware(get_response):
async def middleware(request):
# do something interesting
response = await get_response(request)
return response
return middleware
由于中间件可以支持同步和异步请求的任何组合,如果只支持一种类型的请求(比如上面的例子中只支持异步请求),Django会尽量满足中间件的要求--但会在性能上有所损失。建议使用sync_and_async_middleware 装饰器来定义支持两种请求的中间件。更多的例子可以在文档中找到。
ASGI是必须的吗?
Django的所有异步功能在WSGI和ASGI上都是完全支持的--尽管如果你用WSGI运行异步代码会有性能上的损失,而且长时间运行的请求也不会有效率。如果你想让你的同步代码与你全新的异步视图和ASGI模式很好的配合,建议使用sync_to_async装饰器。
在哪里使用异步视图?
如果你在一个视图中进行大量的外部HTTP调用,异步视图允许你在原生的情况下进行这些调用。这可以提供很大的加速,特别是如果你之前在同步视图中使用了异步代码。如果你的视图涉及到繁重的计算或长期运行的网络调用,作为请求路径的一部分,这是使用异步视图的一个伟大的用例。
在Django中你还不能使用async的地方
ORM、缓存层以及其他一些涉及到长期网络调用的代码部分还不支持async。ORM中对async功能的支持预计会更快到来,因为它是初始DEP的一部分。像模板和缓存后端这样的功能还需要一些时间,因为这些功能需要有自己单独的DEP和研究来实现完全异步。
总结
Django 3.0开始了为Django带来完全异步功能的旅程,首先是增加了对ASGI的支持,可以运行同步代码。有了这个版本,如果你不需要对Django的一些还不支持async的部分做繁琐的处理,你实际上可以把async代码放到生产中。所有的改变都能保证100%向后兼容,这本身就是一个令人印象深刻的壮举--这也保证了Django很快就能完全支持async的光明前景