带有 aiohttp 客户端的异步 Django 3.1

Async Django 3.1 with aiohttp client

在开始将 django 移植到 async 之后,现在可以在 django 中使用 aiohttp 客户端吗?

我的情况:

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

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

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


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

您可以像这样在 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。

重要说明: 当然,你应该 运行 你的 Django 应用程序在 ASGI 模式下与一些兼容的应用程序服务器(例如 uvicorn):

uvicorn my_project.asgi:application --reload

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

shared.py:

from typing import Optional
from aiohttp import ClientSession


AIOHTTP_SESSION: Optional[ClientSession] = None

settings.py:

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

views.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()

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

tests.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 测试