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
恢复 async
和 await
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()),
]
)
)
)
})
试试这个:
- 从
django.core.asgi
. 导入 get_asgi_application
- 允许 Django 的 ASGI 应用程序处理传统的
http
请求,方法是在 ProtocolTypeRouter
.[= 中的字典中添加 http
作为键和 get_asgi_application()
作为键值31=]
- 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 的更多信息。
我正在使用 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
恢复 async
和 await
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()),
]
)
)
)
})
试试这个:
- 从
django.core.asgi
. 导入 - 允许 Django 的 ASGI 应用程序处理传统的
http
请求,方法是在ProtocolTypeRouter
.[= 中的字典中添加http
作为键和get_asgi_application()
作为键值31=] - use/call
as_asgi()
类方法同时路由ChatConsumer
消费者。
get_asgi_application
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 的更多信息。