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 超出容量”

来自 Consumers.py 外部的 Django 通道消息

在 Angular6 前端使用 Django 通道

将数据发送到 Django 通道

连接rabbitmq,芹菜和django时出现通道错误