django 3和django通道中的SynchronousOnlyOperation错误
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django 3和django通道中的SynchronousOnlyOperation错误相关的知识,希望对你有一定的参考价值。
我有一个django 2应用,我使用django通道进行套接字连接。
我只是将django更新到版本3。现在,当我尝试建立套接字连接时,daphne显示此错误。我对Django 2没有任何问题。
[Failure instance: Traceback: <class 'django.core.exceptions.SynchronousOnlyOperation'>: You cannot call this from an async context - use a thread or sync_to_async.
/home/ubuntu/pl_env/lib/python3.6/site-packages/autobahn/websocket/protocol.py:2844:processHandshake
/home/ubuntu/pl_env/lib/python3.6/site-packages/txaio/tx.py:429:as_future
/home/ubuntu/pl_env/lib/python3.6/site-packages/twisted/internet/defer.py:151:maybeDeferred
/home/ubuntu/pl_env/lib/python3.6/site-packages/daphne/ws_protocol.py:83:onConnect
--- <exception caught here> ---
/home/ubuntu/pl_env/lib/python3.6/site-packages/twisted/internet/defer.py:151:maybeDeferred
/home/ubuntu/pl_env/lib/python3.6/site-packages/daphne/server.py:201:create_application
/home/ubuntu/pl_env/lib/python3.6/site-packages/channels/routing.py:54:__call__
/home/ubuntu/pl_env/lib/python3.6/site-packages/channels/security/websocket.py:37:__call__
/home/ubuntu/petroline_django/orders/token_auth.py:25:__call__
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/manager.py:82:manager_method
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/query.py:411:get
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/query.py:258:__len__
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/query.py:1261:_fetch_all
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/query.py:57:__iter__
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/db/models/sql/compiler.py:1142:execute_sql
/home/ubuntu/pl_env/lib/python3.6/site-packages/django/utils/asyncio.py:24:inner
它说问题出在token_auth.py,第25行。此行是token = Token.objects.get(key=token_key)
这是我的token_auth.py,用于处理令牌身份验证。
from channels.auth import AuthMiddlewareStack
from django.contrib.auth.models import AnonymousUser
from django.db import close_old_connections
from rest_framework.authtoken.models import Token
class TokenAuthMiddleware:
"""
Token authorization middleware for Django Channels 2
see:
https://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication
"""
def __init__(self, inner):
self.inner = inner
def __call__(self, scope):
headers = dict(scope['headers'])
if b'authorization' in headers:
try:
token_name, token_key = headers[b'authorization'].decode().split()
if token_name == 'Token':
# Close old database connections to prevent usage of timed out connections
close_old_connections()
token = Token.objects.get(key=token_key)
scope['user'] = token.user
except Token.DoesNotExist:
scope['user'] = AnonymousUser()
return self.inner(scope)
TokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))
答案
参考this part of the documentation。在那里说明了,如果您尝试在异步上下文中使用ORM(似乎是这种情况),则Django 3将引发此类异常。
作为Django Channels documentation explains的解决方案将如下使用sync_to_async
:
from channels.db import database_sync_to_async class TokenAuthMiddleware: # more code here def __call__(self, scope): # and some more code here token = await database_sync_to_async(Token.objects.get(key=token_key))()
尽管请记住我一生中没有使用过它,所以它可能会失败。
以上是关于django 3和django通道中的SynchronousOnlyOperation错误的主要内容,如果未能解决你的问题,请参考以下文章
Django 通道 websocket 连接和断开连接(Nginx + Daphne + Django + Channels)
Django 频道“组订阅中 N 个频道中的 ERROR Y 超出容量”