Django Channels group send 仅将消息发送到最后一个频道

Django Channels group send only sends the message to last channel

我正在使用 django channels-3.0.3,group_send 仅将我的消息发送到最后连接的频道给连接的用户次。

设置

...
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "chat",
    "channels",
]

ASGI_APPLICATION = "cfehome.routing.application"

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_redis.core.RedisChannelLayer",
        "CONFIG": {
            "hosts": [("127.0.0.1", 6379)],
        },
    },
}

chat/consumers.py

import asyncio
import json
from django.contrib.auth import get_user_model
from channels.consumer import AsyncConsumer
from channels.db import database_sync_to_async

from .models import Thread, ChatMessage


class ChatConsumer(AsyncConsumer):
    @database_sync_to_async
    def get_thread(self, user, other_username):
        return Thread.objects.get_or_new(user, other_username)[0]

    async def websocket_connect(self, event):
        other_user = self.scope['url_route']['kwargs']['username']
        me = self.scope['user']
        # print("connect!")
        # print(me, other_user)
        thread_obj = await self.get_thread(me, other_user)
        # print(me, thread_obj)
        chat_room = f"thread_{thread_obj.id}"
        self.chat_room = chat_room
        await self.channel_layer.group_add(
            chat_room,
            self.channel_name
        )
        print(f"{self.channel_name}, {self.chat_room}, {me} - connected!")
        await self.send({
            "type": "websocket.accept"
        })

    async def websocket_receive(self, event):
        print("msg recevied!", event)
        front_text = event.get("text", None)
        if front_text is not None:
            loaded_dic_Data = json.loads(front_text)
            msg = loaded_dic_Data.get("message")
            # print(msg)
            user = self.scope['user']
            username = "default"
            if user.is_authenticated:
                username = user.username
            myResponse = {
                "message": msg,
                "username": username
            }

            # brodcast msg to chatroom
            await self.channel_layer.group_send(
                self.chat_room,
                {
                    "type": "chat_message",
                    "text": json.dumps(myResponse),
                }
            )

    #  sends the actual msg
    async def chat_message(self, event):
        await self.send({
            "type": "websocket.send",
            "text": event["text"]

        })

    async def websocket_disconnect(self, event):
        print("disconnect!")
        await self.channel_layer.group_discard(
            self.chat_room,
            self.channel_name
        )

在 consumers.py 我也尝试 async_to_sync 恢复 asyncawait

chat/templates/chat/threads.html(我的渲染模板)

{% extends "base.html" %}

{% block content %}
<h3>Thread for {% if user != object.first %}{{ object.first }}{% else %}{{ object.second }}{% endif %}</h3>
<ul id='chat-items'>
{% for chat in object.chatmessage_set.all %}

<li>{{ chat.message }} via {{ chat.user }}</li>

{% endfor %}
</ul>

<form id='form' method='POST'> {% csrf_token %}
    <input type="hidden" id="myUsername" value="{{ user.username }}">
{{form.as_p }}
<input type='submit' class='btn btn-primary'/>
</form>

{% endblock %}

{% block script %}

<script>
// websocket scripts
var loc = window.location;

var formData = $("#form")
var msg = $("#id_message")
var chatHoler = $("#chat-items")
var me = $("#myUsername").val()

var wsStart = "ws://";
if(loc.protocol == "https:"){
    wsStart = "wss://"
};
var endpoint =  wsStart + loc.host + loc.pathname;
var socket = new WebSocket(endpoint);

console.log(endpoint)

socket.onmessage = function(e){
    console.log("message ",e)
    var chatDataMsg = JSON.parse(e.data)
    chatHoler.append("<li>" + chatDataMsg.message + "  -  " + chatDataMsg.username + "</li>")
};
socket.onopen = function(e){
    console.log("open ",e)
    formData.submit(function(event){
        event.preventDefault()
        var msgText = msg.val()
        // chatHoler.append("<li>" + msgText + " via " + me +"</li>")

        var finalData = {
            "message": msgText,
        }
        socket.send(JSON.stringify(finalData))
        formData[0].reset()
    });
};
socket.onerror = function(e){
    console.log("error ",e)
};
socket.onclose = function(e){
    console.log("close ",e)
};

</script>
{% endblock %}

它从一个频道接收消息并发送回该频道,达到 chat_room 中已连接频道的数量。

~提前致谢..这是我在现场的第一个问题:)

已更新! 这是我的 routing.py 文件

from django.conf.urls import url
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator

from chat.consumers import ChatConsumer

application = ProtocolTypeRouter({
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter(
                [
                    url(r"^messages/(?P<username>[\w.@+-]+)/$", ChatConsumer()),
                ]
            )
        )
    )
})

试试这个:

  1. django.core.asgi.
  2. 导入 get_asgi_application
  3. 允许 Django 的 ASGI 应用程序处理传统的 http 请求,方法是在 ProtocolTypeRouter.[= 中的字典中添加 http 作为键和 get_asgi_application() 作为键值31=]
  4. use/call as_asgi() 类方法同时路由 ChatConsumer 消费者。

routing.py

from django.conf.urls import url
from django.core.asgi import get_asgi_application #Change No.1

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator, OriginValidator

from chat.consumers import ChatConsumer

application = ProtocolTypeRouter({
    "http": get_asgi_application(), #Change No.2
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                url(r"^messages/(?P<username>[\w.@+-]+)/$", ChatConsumer.as_asgi()), #Change No.3
           ])
        )
    )
})

有关 channels.readthedocs.io 的更多信息。