首页 > 解决方案 > 带有 aiohttp 客户端的异步 Django 3.1

问题描述

现在是否有可能在开始将 django 移植到异步后使用 django 的 aiohttp 客户端?

我的情况:

  1. 服务器收到请求;
  2. 服务器向另一台服务器发送另一个请求;
  3. 服务器解码响应,将其保存到数据库中,并将响应返回给客户端;

Andrew Svetlov 在两年前提到 aiohttp“从未打算与同步 WSGI 一起工作”。( https://github.com/aio-libs/aiohttp/issues/3357 )

但现在情况如何?Django 似乎几乎支持异步视图。我们可以将 aiohttp 与 asgi django 一起使用吗?


我知道,我可以创建一个处理请求的 aiohttp 服务器,然后填充一些队列,以及将响应保存到数据库中的队列处理程序,但是在这里我从 django 中遗漏了很多:ORM、admin 等。

标签: djangoasync-awaitaiohttp

解决方案


你可以像这样在 Django 3.1 中实现这个场景:

async def my_proxy(request):
    async with ClientSession() as session:
        async with session.get('https://google.com') as resp:
            print(resp.status)
            print(await resp.text())

但对我来说最大的问题是如何在 django 项目中共享一个 aiohttp 会话,因为强烈建议不要为每个请求生成一个新的 ClientSession。

重要提示:当然,您应该使用一些兼容的应用程序服务器(例如 uvicorn)以 ASGI 模式运行 django 应用程序:

uvicorn my_project.asgi:application --reload

更新:我找到了解决方法。您可以使用共享全局对象创建一个模块(文件 *.py),并在项目启动时使用项目设置中的 ClientSession 实例填充它:

共享的.py:

from typing import Optional
from aiohttp import ClientSession


AIOHTTP_SESSION: Optional[ClientSession] = None

设置.py:

from aiohttp import ClientSession
from my_project import shared
...
shared.AIOHTTP_SESSION = ClientSession()

视图.py:

from my_project import shared

async def my_proxy(request):
    async with shared.AIOHTTP_SESSION.get('https://google.com') as resp:
         print(resp.status, resp._session)
         await resp.text()

重要 - 进口应该完全相同。当我将它们更改为“从 my_project.shared 导入 AIOHTTP_SESSION”时,我的测试刹车:(

测试.py:

from asyncio import gather
from aiohttp import ClientSession
from django.test import TestCase
from my_project import shared


class ViewTests(TestCase):

    async def test_async_view(self):
        shared.AIOHTTP_SESSION = ClientSession()
        await gather(*[self.async_client.get('/async_view_url') for _ in range(3)])

通过 ./manage.py test 运行测试


推荐阅读