无法在 Django 异步消费者中获取模型数据。在频道和网络套接字中工作
Unable to fetch model data in Django Async conusmers . working in channels and websockets
我正在开发一个使用异步编程的频道和 websockets 的聊天应用程序。我无法在 consumers.py 中获取模型数据/对象,但能够创建一个 .
群里有人发消息,全群回显,但不保存,刷新页面后刷新。
我想在使用 websockets 将消息发送到组时将消息保存在数据库中。但是我遇到了问题。
这是我的consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from chat.models import ChatMessage , ChatRoom
from channels.db import database_sync_to_async
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.roomId = self.scope['url_route']['kwargs']['roomId']
self.room_group_name = 'chat_group_%s' % self.roomId
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self , close_code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
roomId = text_data_json["roomId"]
roomName = text_data_json["roomName"]
await self.save_message(message , username , roomId , roomName)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'the_message',
'message': message
}
)
async def the_message(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
@sync_to_async
def save_message(self , message , username , roomId , roomName) :
user = User.objects.get(username = username)
the_room = ChatRoom.objects.get(roomname = roomName , id = roomId)
new_message = ChatMessage(user = user , chatroom = the_room , message = message )
new_message.save()
这是我的models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
class ChatRoom(models.Model) :
host = models.ForeignKey(User , on_delete = models.CASCADE)
roomname = models.CharField(max_length = 100 , blank = False , null = False)
participants = models.ManyToManyField(User , verbose_name = "participants" , related_name = "participants")
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
class Meta:
ordering = ["-updated" , "-created"]
def __str__(self) :
return str(self.host) + " created " + str(self.roomname)
class ChatMessage(models.Model) :
user = models.ForeignKey(User , on_delete = models.CASCADE)
chatroom = models.ForeignKey(ChatRoom , on_delete = models.CASCADE)
message = models.CharField(max_length = 200 )
created_timestamp = models.DateTimeField(auto_now = True)
updated_timestamp = models.DateTimeField(auto_now_add = True)
class Meta :
ordering = ["-created_timestamp"]
def __str__(self) :
return str(self.writer) + " commented " + str(self.message)[:10]
当我 运行 这样做时,我收到以下错误。
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:54543]
关于尝试其他一些选项:
Printing just the user with this code bit and commenting the save_mesage method .
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
roomId = text_data_json["roomId"]
roomName = text_data_json["roomName"]
user = User.objects.get(username = username)
print(user)
我收到这个错误 ->
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
很好,我不能使用同步方法在异步程序中获取数据。
但是当我尝试这个时 ->
user = await User.objects.get(username = username)
print(user)
我在上面得到了同样的错误。
再次尝试其他方式
像这样
user = await database_sync_to_async(User.objects.get(username = username))()
print(user)
我得到同样的错误。
再试一次 ->
user = await sync_to_async(User.objects.get(username = username))()
print(user)
出现同样的错误。
现在我尝试像这样从 save_message 函数访问用户模型数据 ->
@sync_to_async
def save_message(self , message , username , roomId , roomName) :
user = database_sync_to_async(User.objects.get(username = username))()
print(user)
我收到这个错误 ->
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:58689]
关于用户存在与否,我是应用程序中的当前登录用户,我只是在发消息。所以毫无疑问用户不存在。
也在尝试这种方式->
user = await User.objects.get(username = username)
await print(user)
这是错误 ->
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/12/ [127.0.0.1:65524]
这是整个错误日志 ->
D:\Programming\Python\Django project\chatsite\chat\consumers.py changed, reloading.
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
March 19, 2022 - 19:28:58
Django version 4.0.2, using settings 'chatsite.settings'
Starting ASGI/Channels version 3.0.4 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
HTTP GET /chat/12/ 200 [0.06, 127.0.0.1:58686]
WebSocket HANDSHAKING /ws/chat/12/ [127.0.0.1:58689]
WebSocket CONNECT /ws/chat/12/ [127.0.0.1:58689]
Exception inside application: User matching query does not exist.
Traceback (most recent call last):
File "C:\Users\user\anaconda3\lib\site-packages\channels\staticfiles.py", line 44, in __call__
return await self.application(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\routing.py", line 71, in __call__
return await application(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\sessions.py", line 47, in __call__
return await self.inner(dict(scope, cookies=cookies), receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\sessions.py", line 263, in __call__
return await self.inner(wrapper.scope, receive, wrapper.send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\auth.py", line 185, in __call__
return await super().__call__(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\middleware.py", line 26, in __call__
return await self.inner(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\routing.py", line 150, in __call__
return await application(
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 94, in app
return await consumer(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 58, in __call__
await await_many_dispatch(
File "C:\Users\user\anaconda3\lib\site-packages\channels\utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 73, in dispatch
await handler(message)
File "C:\Users\user\anaconda3\lib\site-packages\channels\generic\websocket.py", line 194, in websocket_receive
await self.receive(text_data=message["text"])
File "D:\Programming\Python\Django project\chatsite\chat\consumers.py", line 33, in receive
await self.save_message(message , username , roomId , roomName)
File "C:\Users\user\anaconda3\lib\site-packages\asgiref\sync.py", line 414, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "C:\Users\user\anaconda3\lib\asyncio\tasks.py", line 442, in wait_for
return await fut
File "C:\Users\user\anaconda3\lib\concurrent\futures\thread.py", line 52, in run
result = self.fn(*self.args, **self.kwargs)
File "C:\Users\user\anaconda3\lib\site-packages\asgiref\sync.py", line 455, in thread_handler
return func(*args, **kwargs)
File "D:\Programming\Python\Django project\chatsite\chat\consumers.py", line 53, in save_message
user = database_sync_to_async(User.objects.get(username = username))()
File "C:\Users\user\anaconda3\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\user\anaconda3\lib\site-packages\django\db\models\query.py", line 439, in get
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:58689]
我已经尝试了所有可能的组合,无论是否有效,但无法获得 运行ning 程序。
请帮助我。我坚持了好几天。一天又一周。
任何帮助都会很棒。谢谢
其实程序没有问题。问题出在通过 websockets 的 json 数据的 return 数据类型中。通过websockets发送消息时,以json数据的形式发送,键值对中有字符串类型。因此,当发送数据时,额外的引号也被考虑在内,数据不仅是字符串类型的用户名,实际上是以字符串的形式在末尾加上额外的引号。
例如 -> 当前用户的用户名是 xyz123 ,则以 "xyz123" 的形式发送。解决方案只是截断最后两个引号,我们做到了。
这是工作代码。
@sync_to_async
def save_message(self , message , username, roomId , roomName ) :
username = username[1:-1]
roomName = roomName[1:-1]
user = User.objects.get(username = str(username))
room = ChatRoom.objects.get(roomname = roomName, id = int(roomId))
message = ChatMessage(user = user , chatroom = room , message = str(message))
message.save()
print(message)
我正在开发一个使用异步编程的频道和 websockets 的聊天应用程序。我无法在 consumers.py 中获取模型数据/对象,但能够创建一个 .
群里有人发消息,全群回显,但不保存,刷新页面后刷新。 我想在使用 websockets 将消息发送到组时将消息保存在数据库中。但是我遇到了问题。
这是我的consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from chat.models import ChatMessage , ChatRoom
from channels.db import database_sync_to_async
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.roomId = self.scope['url_route']['kwargs']['roomId']
self.room_group_name = 'chat_group_%s' % self.roomId
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self , close_code):
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
roomId = text_data_json["roomId"]
roomName = text_data_json["roomName"]
await self.save_message(message , username , roomId , roomName)
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'the_message',
'message': message
}
)
async def the_message(self, event):
message = event['message']
await self.send(text_data=json.dumps({
'message': message
}))
@sync_to_async
def save_message(self , message , username , roomId , roomName) :
user = User.objects.get(username = username)
the_room = ChatRoom.objects.get(roomname = roomName , id = roomId)
new_message = ChatMessage(user = user , chatroom = the_room , message = message )
new_message.save()
这是我的models.py
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
class ChatRoom(models.Model) :
host = models.ForeignKey(User , on_delete = models.CASCADE)
roomname = models.CharField(max_length = 100 , blank = False , null = False)
participants = models.ManyToManyField(User , verbose_name = "participants" , related_name = "participants")
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
class Meta:
ordering = ["-updated" , "-created"]
def __str__(self) :
return str(self.host) + " created " + str(self.roomname)
class ChatMessage(models.Model) :
user = models.ForeignKey(User , on_delete = models.CASCADE)
chatroom = models.ForeignKey(ChatRoom , on_delete = models.CASCADE)
message = models.CharField(max_length = 200 )
created_timestamp = models.DateTimeField(auto_now = True)
updated_timestamp = models.DateTimeField(auto_now_add = True)
class Meta :
ordering = ["-created_timestamp"]
def __str__(self) :
return str(self.writer) + " commented " + str(self.message)[:10]
当我 运行 这样做时,我收到以下错误。
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:54543]
关于尝试其他一些选项:
Printing just the user with this code bit and commenting the save_mesage method .
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
roomId = text_data_json["roomId"]
roomName = text_data_json["roomName"]
user = User.objects.get(username = username)
print(user)
我收到这个错误 ->
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
很好,我不能使用同步方法在异步程序中获取数据。
但是当我尝试这个时 ->
user = await User.objects.get(username = username)
print(user)
我在上面得到了同样的错误。
再次尝试其他方式
像这样
user = await database_sync_to_async(User.objects.get(username = username))()
print(user)
我得到同样的错误。
再试一次 ->
user = await sync_to_async(User.objects.get(username = username))()
print(user)
出现同样的错误。
现在我尝试像这样从 save_message 函数访问用户模型数据 ->
@sync_to_async
def save_message(self , message , username , roomId , roomName) :
user = database_sync_to_async(User.objects.get(username = username))()
print(user)
我收到这个错误 ->
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:58689]
关于用户存在与否,我是应用程序中的当前登录用户,我只是在发消息。所以毫无疑问用户不存在。
也在尝试这种方式->
user = await User.objects.get(username = username)
await print(user)
这是错误 ->
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/12/ [127.0.0.1:65524]
这是整个错误日志 ->
D:\Programming\Python\Django project\chatsite\chat\consumers.py changed, reloading.
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
March 19, 2022 - 19:28:58
Django version 4.0.2, using settings 'chatsite.settings'
Starting ASGI/Channels version 3.0.4 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
HTTP GET /chat/12/ 200 [0.06, 127.0.0.1:58686]
WebSocket HANDSHAKING /ws/chat/12/ [127.0.0.1:58689]
WebSocket CONNECT /ws/chat/12/ [127.0.0.1:58689]
Exception inside application: User matching query does not exist.
Traceback (most recent call last):
File "C:\Users\user\anaconda3\lib\site-packages\channels\staticfiles.py", line 44, in __call__
return await self.application(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\routing.py", line 71, in __call__
return await application(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\sessions.py", line 47, in __call__
return await self.inner(dict(scope, cookies=cookies), receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\sessions.py", line 263, in __call__
return await self.inner(wrapper.scope, receive, wrapper.send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\auth.py", line 185, in __call__
return await super().__call__(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\middleware.py", line 26, in __call__
return await self.inner(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\routing.py", line 150, in __call__
return await application(
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 94, in app
return await consumer(scope, receive, send)
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 58, in __call__
await await_many_dispatch(
File "C:\Users\user\anaconda3\lib\site-packages\channels\utils.py", line 51, in await_many_dispatch
await dispatch(result)
File "C:\Users\user\anaconda3\lib\site-packages\channels\consumer.py", line 73, in dispatch
await handler(message)
File "C:\Users\user\anaconda3\lib\site-packages\channels\generic\websocket.py", line 194, in websocket_receive
await self.receive(text_data=message["text"])
File "D:\Programming\Python\Django project\chatsite\chat\consumers.py", line 33, in receive
await self.save_message(message , username , roomId , roomName)
File "C:\Users\user\anaconda3\lib\site-packages\asgiref\sync.py", line 414, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "C:\Users\user\anaconda3\lib\asyncio\tasks.py", line 442, in wait_for
return await fut
File "C:\Users\user\anaconda3\lib\concurrent\futures\thread.py", line 52, in run
result = self.fn(*self.args, **self.kwargs)
File "C:\Users\user\anaconda3\lib\site-packages\asgiref\sync.py", line 455, in thread_handler
return func(*args, **kwargs)
File "D:\Programming\Python\Django project\chatsite\chat\consumers.py", line 53, in save_message
user = database_sync_to_async(User.objects.get(username = username))()
File "C:\Users\user\anaconda3\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\user\anaconda3\lib\site-packages\django\db\models\query.py", line 439, in get
raise self.model.DoesNotExist(
django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.
WebSocket DISCONNECT /ws/chat/12/ [127.0.0.1:58689]
我已经尝试了所有可能的组合,无论是否有效,但无法获得 运行ning 程序。 请帮助我。我坚持了好几天。一天又一周。
任何帮助都会很棒。谢谢
其实程序没有问题。问题出在通过 websockets 的 json 数据的 return 数据类型中。通过websockets发送消息时,以json数据的形式发送,键值对中有字符串类型。因此,当发送数据时,额外的引号也被考虑在内,数据不仅是字符串类型的用户名,实际上是以字符串的形式在末尾加上额外的引号。 例如 -> 当前用户的用户名是 xyz123 ,则以 "xyz123" 的形式发送。解决方案只是截断最后两个引号,我们做到了。
这是工作代码。
@sync_to_async
def save_message(self , message , username, roomId , roomName ) :
username = username[1:-1]
roomName = roomName[1:-1]
user = User.objects.get(username = str(username))
room = ChatRoom.objects.get(roomname = roomName, id = int(roomId))
message = ChatMessage(user = user , chatroom = room , message = str(message))
message.save()
print(message)