python - Django Channels 显示房间中的当前用户

标签 python django websocket django-channels

我试图显示连接到相同 websocket 的当前用户(在我的例子中是聊天室),但我有一个小问题。我想创建一个变量来存储用户并将其通过 websockets 发送到我的前端,我已经实现了这一点,但问题在于。

Consumers.py - 方法 1

class ChatRoomConsumer(AsyncWebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.users: list = []

    @database_sync_to_async
    def create_msg(self, user_id=None, message=None, room=None):
        if user_id is not None:
            sender = User.objects.get(id=user_id)
            msg = Message.objects.create(
                author=sender, message=message, room_name=room)
            msg.save()
            return msg
        else:
            get_msgs = Message.objects.filter(room_name__in=[room])
            serializer = MessageSerializer(get_msgs, many=True)

            return serializer.data

    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'

        self.messages = await self.create_msg(room=self.room_name)
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        await self.send(text_data=json.dumps({
            'db_messages': self.messages,

        }))

    async def disconnect(self, close_code):

        print(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)
        type = text_data_json['type']
        message = text_data_json['message']
        username = text_data_json['username']
        user_id = text_data_json['user_id']
        self.user_id = text_data_json['user_id']

        if type == 'chatroom_message':
            self.msg = await self.create_msg(user_id, message, self.room_name)

        await self.channel_layer.group_send(
            self.room_group_name, {
                'type': type,
                'message': message,
                'username': username,
                'user_id': user_id
            }
        )

    async def chatroom_message(self, event):
        message = event['message']
        username = event['username']

        await self.send(text_data=json.dumps({
            'message': message,
            'username': username,
        }))

    # nefunkcni ukazatel momentalnich uzivatelu v mistnosti
    async def get_user(self, event):
        print('get_user called')

        if event['message'] == 'disconnect':
            print('remove', event['username'])
            try:
                self.users.remove(event['username'])
            except ValueError:
                print('user already removed')
        else:
            if event['username'] not in self.users:
                self.users.append(event['username'])
            print(self.users)
        await self.send(text_data=json.dumps({
            'users': self.users
        }))

通过这种方法,它在第一个进入聊天的用户的 View 中正确显示当前登录的用户,其他用户看不到,因此在他们之前加入的用户就在那里。 在这种方法中,我在构造函数中定义变量users

Consumers.py - 方法 2

from channels.generic.websocket import AsyncWebsocketConsumer
from channels.db import database_sync_to_async
from .models import Message
from .serializers import MessageSerializer
from django.contrib.auth.models import User
from django.db.models import Prefetch
from django.core.serializers.json import DjangoJSONEncoder
from asgiref.sync import sync_to_async, async_to_sync
import channels
import json

users: list = []
class ChatRoomConsumer(AsyncWebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        #self.users: list = []

    @database_sync_to_async
    def create_msg(self, user_id=None, message=None, room=None):
        if user_id is not None:
            sender = User.objects.get(id=user_id)
            msg = Message.objects.create(
                author=sender, message=message, room_name=room)
            msg.save()
            return msg
        else:
            get_msgs = Message.objects.filter(room_name__in=[room])
            serializer = MessageSerializer(get_msgs, many=True)

            return serializer.data

    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'

        self.messages = await self.create_msg(room=self.room_name)
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

        await self.send(text_data=json.dumps({
            'db_messages': self.messages,

        }))

    async def disconnect(self, close_code):

        print(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)
        type = text_data_json['type']
        message = text_data_json['message']
        username = text_data_json['username']
        user_id = text_data_json['user_id']
        self.user_id = text_data_json['user_id']

        if type == 'chatroom_message':
            self.msg = await self.create_msg(user_id, message, self.room_name)

        await self.channel_layer.group_send(
            self.room_group_name, {
                'type': type,
                'message': message,
                'username': username,
                'user_id': user_id
            }
        )

    async def chatroom_message(self, event):
        message = event['message']
        username = event['username']

        await self.send(text_data=json.dumps({
            'message': message,
            'username': username,
        }))

    # nefunkcni ukazatel momentalnich uzivatelu v mistnosti
    async def get_user(self, event):
        print('get_user called')

        if event['message'] == 'disconnect':
            print('remove', event['username'])
            try:
                users.remove(event['username'])
            except ValueError:
                print('user already removed')
        else:
            if event['username'] not in users:
                users.append(event['username'])
            print(users)
        await self.send(text_data=json.dumps({
            'users': users
        }))

在此方法中,用户可以正确显示,不是来自当前房间的用户(它显示来自所有其他房间的用户)。这有点合乎逻辑,因为变量的声明位于顶层。

但我的问题是我应该在哪里声明它?当它位于构造函数中时,它始终会覆盖当前用户之前所在房间的用户,而当它位于顶层时,它会获取所有房间中的所有用户。

最佳答案

如果您还没有找到答案,这是我的 2 美分:

消费者是单例的,这意味着每个 channel (websocket 连接)都有一个实例。所以这可能是消费者类中存在用户的问题。

另一种方法是为用户提供字典,而不是数组。所以你可以拥有每个房间的 key ,如下所示: users = { "room_1": [], "room_2": [] }

我知道我的答案中没有代码,但我希望它可以作为您解决方案的指南!

关于python - Django Channels 显示房间中的当前用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71460004/

相关文章:

限制可能值的 Python 类型提示友好类型

python - 帮助开发人员更快阅读类层次结构的工具

django - 在 Django 中,你能自动映射 URL 以查看方法吗?

python - 具有多个应用程序的 Django 静态文件

javascript - 客户端 Socket.io 持续断开并重新连接到 websocket

python - 如何使用 Google Vision API 和 Python 改进 OCR 结果?

python - 如何在目录中的文件上运行gunicorn?

django - Django ModelForm 和 models.Model 有什么区别?

php - html5 websockets php开发的理想平台

sockets - TCP sockets 和 web sockets 的区别,再来一次