Django 通道异步 Websocket 在尝试使用数据库查询时抛出错误
Django channels Async Websocket throwing Error while trying to use database query
我不明白。即使我已经在异步等待中转换了所有必填字段。但我仍然收到以下错误:
HTTP GET /chat/8/ 200 [0.02, 127.0.0.1:51354]
WebSocket HANDSHAKING /ws/chat/8/ [127.0.0.1:51356]
Exception inside application: You cannot call this from an async context - use a thread or sync_to_async.
Traceback (most recent call last):
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/consumer.py", line 58, in __call__
await await_many_dispatch(
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
await self.connect()
File "/media/fahadmdkamal/WORK/B-DOPS/api/chat/consumers.py", line 23, in connect
other_user = await sync_to_async(User.objects.get(id=others_id))
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 411, in get
num = len(clone)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 258, in __len__
self._fetch_all()
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 1261, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 57, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1150, in execute_sql
cursor = self.connection.cursor()
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
WebSocket DISCONNECT /ws/chat/8/ [127.0.0.1:51356]
错误提示我需要调用 sync_to_async。即使我调用了该函数,我仍然会收到此错误。我想打印从数据库中获取的其他用户。但它甚至没有进入该语句,这意味着我的数据库调用可能不正确。我看过其他人的一些代码结构,这些代码结构与我的完全相同。我错过了什么?
我的消费者代码:
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
# Get message sender information
self.me = self.scope['user']
# print(self.me)
# Get other user's ID from the url
others_id = self.scope['url_route']['kwargs']['user_id']
# Get Other user object using the collected object.
other_user = await sync_to_async(User.objects.get(id=others_id))
print(other_user)
# Get or create personal thread for the conversation
self.thread_obj = await sync_to_async(
Thread.objects.get_or_create_personal_thread(
self.me,
other_user)
)
# Creating room with the thread object id.
self.room_name = f'presonal_thread_{self.thread_obj.id}'
# Adding room and channel name to to the channel layer group
await self.channel_layer.group_add(
self.room_name,
self.channel_name
)
# Accecpting the connection
await self.accept()
print(f'[{self.channel_name}] - You are connected')
# Codes that will be run while disconnecting the websocket
async def disconnect(self, close_code):
print(f'[{self.channel_name}] - Disonnected')
# remove room and channel name from the channel layer
await self.channel_layer.group_discard(
self.room_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
# Decode json raw data that was sent from user
text_data_json = json.loads(text_data)
message = text_data_json['message']
print(f'[{self.channel_name}] - Recieved message - {message}')
# Store the received data
await self.store_message(message=message)
# Send message to room group so that it can send to the all users
await self.channel_layer.group_send(
self.room_name,
{
'type': 'chat_message',
'message': message,
}
)
# Receive message from room group
async def chat_message(self, event):
print(f'[{self.channel_name}] - Message sent - {event["message"]}')
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'user_id': self.scope['user'].id,
'username': self.scope['user'].username
}))
@database_sync_to_async
def store_message(self, message):
Message.objects.create(sender=self.me,
thread=self.thread_obj,
message=message)
我的路由代码:
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter([
path('ws/chat/<int:user_id>/', consumers.ChatConsumer)
])
),
})
由于我是 django 频道的新手,如果您能说整个 AsyncWebsocketConsumer 结构是否正常,那会更有帮助吗?
哦..解决了..
实际上我在构建 await sync_to_async 调用时不正确。
该函数应单独调用,参数应在单独的括号中调用。
旧的和错误的结构:
other_user = await sync_to_async(User.objects.get(id=others_id))
更新和正确的结构:
other_user = await sync_to_async(User.objects.get)(id=others_id)
我在这里调用 sync_to_async 方法在第一个括号中获取用户对象,在第二个括号中我提供查询参数。
我不明白。即使我已经在异步等待中转换了所有必填字段。但我仍然收到以下错误:
HTTP GET /chat/8/ 200 [0.02, 127.0.0.1:51354]
WebSocket HANDSHAKING /ws/chat/8/ [127.0.0.1:51356]
Exception inside application: You cannot call this from an async context - use a thread or sync_to_async.
Traceback (most recent call last):
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/sessions.py", line 183, in __call__
return await self.inner(receive, self.send)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/middleware.py", line 41, in coroutine_call
await inner_instance(receive, send)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/consumer.py", line 58, in __call__
await await_many_dispatch(
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/consumer.py", line 73, in dispatch
await handler(message)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/channels/generic/websocket.py", line 175, in websocket_connect
await self.connect()
File "/media/fahadmdkamal/WORK/B-DOPS/api/chat/consumers.py", line 23, in connect
other_user = await sync_to_async(User.objects.get(id=others_id))
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 411, in get
num = len(clone)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 258, in __len__
self._fetch_all()
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 1261, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/query.py", line 57, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1150, in execute_sql
cursor = self.connection.cursor()
File "/media/fahadmdkamal/WORK/B-DOPS/api/env/lib/python3.8/site-packages/django/utils/asyncio.py", line 24, in inner
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
WebSocket DISCONNECT /ws/chat/8/ [127.0.0.1:51356]
错误提示我需要调用 sync_to_async。即使我调用了该函数,我仍然会收到此错误。我想打印从数据库中获取的其他用户。但它甚至没有进入该语句,这意味着我的数据库调用可能不正确。我看过其他人的一些代码结构,这些代码结构与我的完全相同。我错过了什么?
我的消费者代码:
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
# Get message sender information
self.me = self.scope['user']
# print(self.me)
# Get other user's ID from the url
others_id = self.scope['url_route']['kwargs']['user_id']
# Get Other user object using the collected object.
other_user = await sync_to_async(User.objects.get(id=others_id))
print(other_user)
# Get or create personal thread for the conversation
self.thread_obj = await sync_to_async(
Thread.objects.get_or_create_personal_thread(
self.me,
other_user)
)
# Creating room with the thread object id.
self.room_name = f'presonal_thread_{self.thread_obj.id}'
# Adding room and channel name to to the channel layer group
await self.channel_layer.group_add(
self.room_name,
self.channel_name
)
# Accecpting the connection
await self.accept()
print(f'[{self.channel_name}] - You are connected')
# Codes that will be run while disconnecting the websocket
async def disconnect(self, close_code):
print(f'[{self.channel_name}] - Disonnected')
# remove room and channel name from the channel layer
await self.channel_layer.group_discard(
self.room_name,
self.channel_name
)
# Receive message from WebSocket
async def receive(self, text_data):
# Decode json raw data that was sent from user
text_data_json = json.loads(text_data)
message = text_data_json['message']
print(f'[{self.channel_name}] - Recieved message - {message}')
# Store the received data
await self.store_message(message=message)
# Send message to room group so that it can send to the all users
await self.channel_layer.group_send(
self.room_name,
{
'type': 'chat_message',
'message': message,
}
)
# Receive message from room group
async def chat_message(self, event):
print(f'[{self.channel_name}] - Message sent - {event["message"]}')
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message,
'user_id': self.scope['user'].id,
'username': self.scope['user'].username
}))
@database_sync_to_async
def store_message(self, message):
Message.objects.create(sender=self.me,
thread=self.thread_obj,
message=message)
我的路由代码:
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter([
path('ws/chat/<int:user_id>/', consumers.ChatConsumer)
])
),
})
由于我是 django 频道的新手,如果您能说整个 AsyncWebsocketConsumer 结构是否正常,那会更有帮助吗?
哦..解决了..
实际上我在构建 await sync_to_async 调用时不正确。 该函数应单独调用,参数应在单独的括号中调用。
旧的和错误的结构:
other_user = await sync_to_async(User.objects.get(id=others_id))
更新和正确的结构:
other_user = await sync_to_async(User.objects.get)(id=others_id)
我在这里调用 sync_to_async 方法在第一个括号中获取用户对象,在第二个括号中我提供查询参数。