Home:ALL Converter>SynchronousOnlyOperation Error in with django 3 and django channels

SynchronousOnlyOperation Error in with django 3 and django channels

Ask Time:2020-01-08T00:13:48         Author:AlexMercer

Json Formatter

I had a django 2 app and i used django channels for socket connection.

i just update django to version 3. and now daphne show this error when i try to make a socket connection. i had not any problem with 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

it says the problem is in token_auth.py, line 25. this line is token = Token.objects.get(key=token_key)

this is my token_auth.py that handles token authentication.

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))

Author:AlexMercer,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/59632125/synchronousonlyoperation-error-in-with-django-3-and-django-channels
AlexMercer :

Thanks to @ivissani answers, i fixed my TokenAuthMiddleware with some of SessionMiddleware codes. \n\nI have opened an issue for django channels about updating docs.\n\n@database_sync_to_async\ndef get_user(token_key):\n try:\n return Token.objects.get(key=token_key).user\n except Token.DoesNotExist:\n return AnonymousUser()\n\n\nclass TokenAuthMiddleware:\n \"\"\"\n Token authorization middleware for Django Channels 2\n see:\n https://channels.readthedocs.io/en/latest/topics/authentication.html#custom-authentication\n \"\"\"\n\n def __init__(self, inner):\n self.inner = inner\n\n def __call__(self, scope):\n return TokenAuthMiddlewareInstance(scope, self)\n\n\nclass TokenAuthMiddlewareInstance:\n def __init__(self, scope, middleware):\n self.middleware = middleware\n self.scope = dict(scope)\n self.inner = self.middleware.inner\n\n async def __call__(self, receive, send):\n headers = dict(self.scope['headers'])\n if b'authorization' in headers:\n token_name, token_key = headers[b'authorization'].decode().split()\n if token_name == 'Token':\n self.scope['user'] = await get_user(token_key)\n inner = self.inner(self.scope)\n return await inner(receive, send) \n\n\nTokenAuthMiddlewareStack = lambda inner: TokenAuthMiddleware(AuthMiddlewareStack(inner))\n",
2020-01-08T20:26:01
Mathieu Barbot :

Fixed by using @database_sync_to_async decorator:\n\n(see https://github.com/MathieuB1/KOREK-backend/commit/ff6a4b542cda583a1d5abbf200a5d57ef328cae0#diff-95e545fb374a9ed7e8af8c31087a3f29)\n\n\n\nimport jwt, re\nimport traceback\nfrom channels.auth import AuthMiddlewareStack\nfrom channels.db import database_sync_to_async\nfrom django.contrib.auth.models import AnonymousUser\nfrom django.conf import LazySettings\nfrom jwt import InvalidSignatureError, ExpiredSignatureError, DecodeError\nfrom django.contrib.auth.models import User\nfrom django.contrib.sessions.models import Session\n\nsettings = LazySettings()\n\nfrom django.db import close_old_connections\n\n@database_sync_to_async\ndef close_connections():\n close_old_connections()\n\n@database_sync_to_async\ndef get_user(user_jwt):\n try:\n return User.objects.get(id=user_jwt)\n except User.DoesNotExist:\n return AnonymousUser()\n\n\nclass TokenAuthMiddleware:\n \"\"\"\n Token authorization middleware for Django Channels 2\n \"\"\"\n def __init__(self, inner):\n self.inner = inner\n\n def __call__(self, scope):\n # Close old database connections to prevent usage of timed out connections\n close_connections()\n\n # Login with JWT\n try:\n if scope['subprotocols'][0] != 'None':\n\n token = scope['subprotocols'][0]\n\n try:\n user_jwt = jwt.decode(\n token,\n settings.SECRET_KEY,\n )\n scope['user'] = get_user(user_jwt['user_id'])\n return self.inner(scope)\n\n except (InvalidSignatureError, KeyError, ExpiredSignatureError, DecodeError):\n traceback.print_exc()\n pass\n except Exception as e:\n traceback.print_exc()\n else:\n raise\n",
2020-03-06T18:09:53
yy