'Python AsyncJsonWebSocketConsumer Problem
I'm getting that error which
You cannot call this from an async context - use a thread or sync_to_async.
when I run my project. My consumer looks like
class AllConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
self.user_id = str(self.scope['url_route']['kwargs']['user_id'])
await self.accept()
user = sync_to_async(User.objects.get(id=self.user_id))
sync_to_async(OnlineUserActivity.update_user_activity(user))
online_users = []
user_activity_objects = OnlineUserActivity.get_user_activities(timedelta(minutes=1))
for online_user in user_activity_objects:
online_users.append(online_user.user_id)
all_users = User.objects.all().values_list('id')
for _user in all_users:
await self.channel_layer.group_send(
str(_user[0]),
{
"type": "online_users",
'message': online_users
}
)
await self.channel_layer.group_add(
self.user_id,
self.channel_name,
)
async def disconnect(self, close_code):
try:
online_user = OnlineUserActivity.objects.get(user_id=self.user_id)
online_user.delete()
online_users = []
user_activity_objects = OnlineUserActivity.get_user_activities(timedelta(minutes=1))
for x in user_activity_objects:
online_users.append(x.user_id)
all_users = User.objects.all().values_list('id')
for _user in all_users:
await self.channel_layer.group_send(
str(_user[0]),
{
"type": "online_users",
'message': online_users
}
)
except Exception as e:
print(e)
async_to_sync(self.channel_layer.group_discard(
self.user_id,
self.channel_name
))
async def receive(self, text_data):
text_data_json = json.loads(text_data)
socket_type = text_data_json['type']
bla bla. ...
and also my routing py looks like
from django.urls import re_path
from core import consumers
websocket_urlpatterns = [
re_path(r'ws/(?P<user_id>\w+)/$', consumers.AllConsumer),
]
My websockets requests touch my consumer it's okey but it throw an exception like this. My operating system is Ubuntu 18 Everything works without sync to async part, can you help me thanks Main problem, error problem is
You cannot call this from an async context - use a thread or sync_to_async.
Solution 1:[1]
Instead of:
user = sync_to_async(User.objects.get(id=self.user_id))
You should use:
user = await sync_to_async(User.objects.get)(id=self.user_id)
Solution 2:[2]
From the question's reference, The function connect is defined from async context. But in below line, the call is made from sync context :
user = sync_to_async(User.objects.get(id=self.user_id))
sync_to_async does not respect the context of definition of function.
Instead using sync_to_async, use of async_to_sync works like as below :
user = async_to_sync(User.objects.get(id=self.user_id)).awaitable
There is another option as well, that can be used but, its not recommended in production environments. It can referred here in detail :
https://docs.djangoproject.com/en/3.0/topics/async/
I hope this helps.
Solution 3:[3]
I am late, but the correct answer(according to me) should be following
from channels.db import database_sync_to_async
user = await database_sync_to_async(User.objects.get)(id=self.user_id)
Also, if you are using a reference lets say author which is in book use following approach
from channels.db import database_sync_to_async
book = await database_sync_to_async(Book.objects.select_related('author').get)(pk=book_id)
author = book.author
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | jmunsch |
| Solution 2 | |
| Solution 3 | Piyush Kumar |
