当async def call_test(request):
调用async def test():
时,如下所示(我使用Django==3.1.7)):
async def test():
for _ in range(0, 3):
print("Test")
async def call_test(request):
await test() # Here
return HttpResponse("Call_test")
在控制台显示正确的结果没有错误:
Test
Test
Test
但是,当我把@transaction.atomic()
放在async def test():
上时,如下所示:
@transaction.atomic # Here
async def test():
for _ in range(0, 3):
print("Test")
# ...
出现以下错误:
所以,我把django.core.exceptions。SynchronousOnlyOperation:你不能从异步上下文中调用它——使用线程或sync_to_async。
@sync_to_async
放在@transaction.atomic()
下面,如下所示:
@transaction.atomic
@sync_to_async # Here
async def test():
for _ in range(0, 3):
print("Test")
# ...
但是,出现了下面相同的错误:
django.core.exceptions。SynchronousOnlyOperation:你不能调用从异步上下文中-使用线程或sync_to_async。
所以,我把@sync_to_async
放在@transaction.atomic()
上,如下所示:
@sync_to_async # Here
@transaction.atomic
async def test():
for _ in range(0, 3):
print("Test")
# ...
但是,出现以下错误:
RuntimeWarning:协程'test'从未等待过handle = None #发生异常时需要打破循环。RuntimeWarning:启用tracemalloc以获取对象分配跟踪
那么,我如何在Django中使用async
函数?
我也遇到过类似的问题。不同之处在于,我需要使用原子事务作为异步上下文管理器。看完后,很少有人写在Django4.2.4
的当前版本中这是不可能的。开始自己研究代码库。
我注意到的第一件事,transaction.atomic()
不实现逻辑本身。它只是返回Atomic
上下文装饰器。这个装饰器有3个需要处理的重要方法:
__init__
atomic()传递参数给它,所以我们必须处理它们。__enter__
和__exit__
对于上下文管理器的工作很重要。
class Atomic(ContextDecorator):
...
def __init__(self, using, savepoint, durable):
...
def __enter__(self):
...
def __exit__(self, exc_type, exc_value, traceback):
...
def atomic(using=None, savepoint=True, durable=False):
# Bare decorator: @atomic -- although the first argument is called
# `using`, it's actually the function being decorated.
if callable(using):
return Atomic(DEFAULT_DB_ALIAS, savepoint, durable)(using)
# Decorator: @atomic(...) or context manager: with atomic(...): ...
else:
return Atomic(using, savepoint, durable)
异步上下文管理器工作,我们需要实现__aenter__
和__aexit__
。考虑到这一点,我想出了一个可行的解决方案:
from django.db.transaction import Atomic
from asgiref.sync import sync_to_async
class AsyncAtomicContextManager(Atomic):
def __init__(self, using=None, savepoint=True, durable=False):
super().__init__(using, savepoint, durable)
async def __aenter__(self):
await sync_to_async(super().__enter__)()
return self
async def __aexit__(self, exc_type, exc_value, traceback):
await sync_to_async(super().__exit__)(exc_type, exc_value, traceback)
可以用作标准的异步上下文管理器:
async def test():
async with AsyncAtomicContextManager():
...
然后你可以这样做:
def aatomic(fun, *args, **kwargs):
async def wrapper():
async with AsyncAtomicContextManager():
await fun(*args, **kwargs)
return wrapper
@aatomic
async def test():
...
我发现Django 4.1的文档如下:
因此,事务还不能在异步模式下工作。如果您有一段代码需要事务行为,我们建议您将这段代码编写为单个同步函数,并使用sync_to_async()调用它。
@transaction.atomic()
不能与async
函数在order版本Django 3.1.7中使用。。