无法在 Django 异步消费者中获取模型数据。在通道和 websocket 中工作

发布于 2025-01-15 13:30:56 字数 9425 浏览 1 评论 0原文

我正在使用异步编程开发带有通道和网络套接字的聊天应用程序。我无法获取 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]

在尝试其他一些选择时:

仅使用此代码位打印用户并注释 save_mesage 方法。

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]

我已经尝试了所有可能的组合,无论是否有效,但无法获得正在运行的程序。 请帮助我。我被困了好几天了。一天又一天过去了。

任何帮助都会很棒。谢谢

I am working on a chat application with channels and websockets using async programming. I am unable to get the model data / object in consumers.py but able to create one .

As someone in the group sends the message , it is echoed to the whole group but not saved and thus is flushed after the page is refreshed .
I want to save the message in the database as the message is sent to the group using websockets . But I am facing problem.

This is my 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()
        

This is my 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]

when I run this I get the following error .

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]

On trying some other options :

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)

I get this error ->

raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

well this is totally fine that I can't use synchronous methods to get the data in async programs .

but when I try this ->

user = await  User.objects.get(username = username)
        print(user)

I get the same error above .

Again trying some other ways
like this

user = await database_sync_to_async(User.objects.get(username = username))()
        print(user)

I get the same error .

again trying this ->

user = await sync_to_async(User.objects.get(username = username))()
        print(user)

the same error arises .

Now I tried to access the user model data from the save_message function like this ->

@sync_to_async    
    def save_message(self , message , username , roomId , roomName) : 
        user = database_sync_to_async(User.objects.get(username = username))()
        print(user)

I get this error ->

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]

Well talking about the user exists or not , I am the current logged in user in the app and I am only messeging . so there is no doubt the user does not exist .

Also trying this way ->

user = await User.objects.get(username = username)
        await print(user)

this is the error ->

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]

This is the whole error log ->

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]

I have tried every possible combination whether valid or not but unable to get the running program .
Kindly help me . I am stuck it for days. It's going to be a week after a day.

Any help would be great. Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

终弃我 2025-01-22 13:30:56

其实程序并没有什么问题。问题在于通过 websockets 返回 json 数据的数据类型。当消息通过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)

Actually there was no problem in the program . The problem was in the return data type of the json data via websockets . When the messsage was sent via websockets , it was sent in the form of json data , and the key value pair had string type in it . Thus , when the data was sent , the extra quotes were also taken in account and the data instead of being just a username of type string , was actually in the form of a string with extra quotes at the end .
For example -> The username of the current user is xyz123 , then it was sent in the form of "xyz123" . The solution was just to truncate the last two quotes , and we done .

here's the working code.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文