Django Cookiecutter Channels3 - 连接打开,不发送
我使用 Django Cookiecutter w/ Docker 启动了一个项目:https://cookiecutter-django.readthedocs。 io/en/latest/
我正在尝试添加频道并按照其文档中的教程进行操作:https://channels.readthedocs.io/en/stable/tutorial
我添加了 Channels 3.0。 4. 到requirements.txt,重建docker容器。
我向settings/base.py添加了频道,这是:
WSGI_APPLICATION = "config.wsgi.application"
ASGI_APPLICATION = "config.asgi.application"
我更新了我的config/asgi.py文件:
import os
import sys
from pathlib import Path
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from the_pub.chat import routing
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
sys.path.append(str(ROOT_DIR / "the_pub"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
django_application = get_asgi_application()
from config.websocket import websocket_application # noqa isort:skip
application = ProtocolTypeRouter({
"https": django_application,
"websocket": AuthMiddlewareStack(
URLRouter(
routing.websocket_urlpatterns
)
),
})
async def application(scope, receive, send):
if scope["type"] == "http":
await django_application(scope, receive, send)
elif scope["type"] == "websocket":
await websocket_application(scope, receive, send)
else:
raise NotImplementedError(f"Unknown scope type {scope['type']}")
创建了一个config/websocket.io文件
async def websocket_application(scope, receive, send):
while True:
event = await receive()
if event["type"] == "websocket.connect":
await send({"type": "websocket.accept"})
if event["type"] == "websocket.disconnect":
break
if event["type"] == "websocket.receive":
if event["text"] == "ping":
await send({"type": "websocket.send", "text": "pong!"})
视图:
# chat/views.py
from django.shortcuts import render
def index(request):
return render(request, 'chat/index.html')
def index(request):
return render(request, 'chat/index.html', {})
def room(request, room_name):
return render(request, 'chat/room.html', {
'room_name': room_name
})
路由:
# chat/routing.py
from django.urls import re_path
from the_pub.chat import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
]
聊天/网址:
# chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<str:room_name>/', views.room, name='room'),
]
消费者:
# chat/consumers.py
import json
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.accept()
def disconnect(self, close_code):
pass
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
self.send(text_data=json.dumps({
'message': message
}))
app.py
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class ChatConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'the_pub.chat'
verbose_name= _("Chat")
def ready(self):
try:
import the_pub.users.signals # noqa F401
except ImportError:
pass
模板:
<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br>
<input id="chat-message-input" type="text" size="100"><br>
<input id="chat-message-submit" type="button" value="Send">
{{ room_name|json_script:"room-name" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ roomName
+ '/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.message + '\n');
console.log(data);
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
</script>
</body>
</html>
当我测试我可以在 Chrome 插件中使用 websocket 发送消息并记录日志。当我点击表单上的“发送”时,它什么也没做。没有控制台警报,docker 日志中没有任何内容。它所做的只是清除文本框中的文本。我不认为第三方可以检查套接字,因为我将其包装在身份验证层中,但事实恰恰相反,我的应用程序的行为就像将消息发送到套接字的 JavaScript 不存在一样。
当您安装 Channels 时,它会提示执行“pip -m install -U Channels”。我向requirements.txt 基本文件添加了通道,并让django cookiecutter 与其余库一起运行安装。这打破了吗?
另外,我正在运行这个项目,它是由 cookiecutter 设置的,我猜是 wsgi。是否可以像这样同时使用 wsgi 和 asgi,或者我应该考虑如何在 asgi 上运行整个网站?
我在控制台中收到错误“DevTools 无法加载源映射:无法加载 /requestProvider.js.map 的内容。我通常会忽略这些错误,但这与触发 .onmessage 时的 socket.send() 函数可疑相关。
I started a a project with Django Cookiecutter w/ Docker: https://cookiecutter-django.readthedocs.io/en/latest/
I'm trying to add Channels and follow the tutorial in their docs: https://channels.readthedocs.io/en/stable/tutorial
I added Channels 3.0.4 to requirements.txt, rebuilt the docker container.
I added channels to settings/base.py, and this:
WSGI_APPLICATION = "config.wsgi.application"
ASGI_APPLICATION = "config.asgi.application"
I updated my config/asgi.py file:
import os
import sys
from pathlib import Path
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from the_pub.chat import routing
ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent
sys.path.append(str(ROOT_DIR / "the_pub"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
django_application = get_asgi_application()
from config.websocket import websocket_application # noqa isort:skip
application = ProtocolTypeRouter({
"https": django_application,
"websocket": AuthMiddlewareStack(
URLRouter(
routing.websocket_urlpatterns
)
),
})
async def application(scope, receive, send):
if scope["type"] == "http":
await django_application(scope, receive, send)
elif scope["type"] == "websocket":
await websocket_application(scope, receive, send)
else:
raise NotImplementedError(f"Unknown scope type {scope['type']}")
created a config/websocket.io file
async def websocket_application(scope, receive, send):
while True:
event = await receive()
if event["type"] == "websocket.connect":
await send({"type": "websocket.accept"})
if event["type"] == "websocket.disconnect":
break
if event["type"] == "websocket.receive":
if event["text"] == "ping":
await send({"type": "websocket.send", "text": "pong!"})
views:
# chat/views.py
from django.shortcuts import render
def index(request):
return render(request, 'chat/index.html')
def index(request):
return render(request, 'chat/index.html', {})
def room(request, room_name):
return render(request, 'chat/room.html', {
'room_name': room_name
})
routing:
# chat/routing.py
from django.urls import re_path
from the_pub.chat import consumers
websocket_urlpatterns = [
re_path(r'ws/chat/(?P<room_name>\w+)/
chat/urls:
# chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('<str:room_name>/', views.room, name='room'),
]
consumer:
# chat/consumers.py
import json
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.accept()
def disconnect(self, close_code):
pass
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json['message']
self.send(text_data=json.dumps({
'message': message
}))
app.py
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class ChatConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'the_pub.chat'
verbose_name= _("Chat")
def ready(self):
try:
import the_pub.users.signals # noqa F401
except ImportError:
pass
template:
<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Chat Room</title>
</head>
<body>
<textarea id="chat-log" cols="100" rows="20"></textarea><br>
<input id="chat-message-input" type="text" size="100"><br>
<input id="chat-message-submit" type="button" value="Send">
{{ room_name|json_script:"room-name" }}
<script>
const roomName = JSON.parse(document.getElementById('room-name').textContent);
const chatSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/chat/'
+ roomName
+ '/'
);
chatSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
document.querySelector('#chat-log').value += (data.message + '\n');
console.log(data);
};
chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly');
};
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function(e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
document.querySelector('#chat-message-submit').onclick = function(e) {
const messageInputDom = document.querySelector('#chat-message-input');
const message = messageInputDom.value;
chatSocket.send(JSON.stringify({
'message': message
}));
messageInputDom.value = '';
};
</script>
</body>
</html>
When I test the websocket in a chrome plugin I can send messages and it logs. When I hit send on the form it does nothing. no console alerts, nothing in docker logs. All it does is clear the text in the text box. I didn't think a third party could check the socket because I wrapped it in an authentication layer, but it's the opposite, my app acts like the javascript to send the message to the socket doesn't exist.
when you install Channels, it says to do 'pip -m install -U channels'. I added channels to the requirements.txt base file and let django cookiecutter run install with the rest of the libraries. did this break it?
Also, I'm running this project has it was set up by cookiecutter, which I guess is wsgi. Is it even possible to use both wsgi and asgi like this or should I be looking at how to run the whole site on asgi?
I get an error in the console "DevTools failed to load source map: Could not load content for /requestProvider.js.map. I normally ignore these errors but this seams suspiciously related to the socket.send() function on triggering an .onmessage.
, consumers.ChatConsumer.as_asgi()),
]
chat/urls:
consumer:
app.py
template:
When I test the websocket in a chrome plugin I can send messages and it logs. When I hit send on the form it does nothing. no console alerts, nothing in docker logs. All it does is clear the text in the text box. I didn't think a third party could check the socket because I wrapped it in an authentication layer, but it's the opposite, my app acts like the javascript to send the message to the socket doesn't exist.
when you install Channels, it says to do 'pip -m install -U channels'. I added channels to the requirements.txt base file and let django cookiecutter run install with the rest of the libraries. did this break it?
Also, I'm running this project has it was set up by cookiecutter, which I guess is wsgi. Is it even possible to use both wsgi and asgi like this or should I be looking at how to run the whole site on asgi?
I get an error in the console "DevTools failed to load source map: Could not load content for /requestProvider.js.map. I normally ignore these errors but this seams suspiciously related to the socket.send() function on triggering an .onmessage.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您应该从
config/asgi.py.py
中删除async def应用程序(...)
,因为您将应用程序定义为上方的变量。如果使用频道,则不需要
config/websocket.py
文件,因为您正在处理消费者的WebSocket连接。确保 Channels_redis 如果您使用REDIS来用于通道层。
您的
chat/views.py
具有两个索引视图。不确定这是否是故意的,但是当它不起作用时会造成不必要的混乱。You should remove the
async def application(...)
fromconfig/asgi.py
since you are defining the application as a variable right above.If using channels, the
config/websocket.py
file is not exactly needed, since you're handling websocket connections from consumers.Make sure channels_redis is installed if you're using Redis for the channel layer.
Your
chat/views.py
has two index views. Not sure if that's intended, but it will create unnecessary confusion when it doesn't work.