Language/Python
[python] django channels - web socket 연동 (2)
도토리즈
2023. 5. 30. 21:02
- chat/templates/chat/room.html 생성
- room.html
<!-- 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');
};
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>
- chat/views.py에 아래 코드 추가
def room(request, room_name):
return render(request, "chat/room.html", {"room_name": room_name})
- chat/urls.py에 아래 코드 추가
# chat/urls.py
from django.urls import path
from . import views
urlpatterns = [
#...
path("<str:room_name>/", views.room, name="room"),
]
- 채팅 방 생성
but 메시지 입력하면 오류 뜸
콘솔 보면 이런 오류가 떠있음 consumer를 만들어야함
- chat/consumer.py 생성
- consumer.py에 아래 코드 복붙
# 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}))
- chat/routing.py 생성
- routing.py에 아래 코드 복붙
# chat/routing.py
from django.urls import re_path
from . import consumers
websocket_urlpatterns = [
re_path(r"ws/chat/(?P<room_name>\w+)/$", consumers.ChatConsumer.as_asgi()),
]
- config/asgi.py 수정
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
import chat.routing
application = ProtocolTypeRouter(
{
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(URLRouter(chat.routing.websocket_urlpatterns))
),
}
)
- migrate 후 다시 실행
$ python manage.py migrate
$ python manage.py runserver
- 127.0.0.1:8000/chat/lobby/ 접속
이번에 hello라고 입력하면 콘솔 오류도 안뜨고 잘 실행
- 채널 계층 활성화
docker run -p 6379:6379 -d redis:5
Redis를 백업 저장소로 사용하는 채널 계층을 사용
- channels_redis 설치
$ pip install channels_redis
- config/settings.py CHANNEL_LAYERS 추가
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)],
},
},
}
- chat/consumer.py 코드 수정
# chat/consumers.py
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
class ChatConsumer(WebsocketConsumer):
def connect(self):
self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
self.room_group_name = "chat_%s" % self.room_name
# Join room group
async_to_sync(self.channel_layer.group_add)(
self.room_group_name, self.channel_name
)
self.accept()
def disconnect(self, close_code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.room_group_name, self.channel_name
)
# Receive message from WebSocket
def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
# Send message to room group
async_to_sync(self.channel_layer.group_send)(
self.room_group_name, {"type": "chat_message", "message": message}
)
# Receive message from room group
def chat_message(self, event):
message = event["message"]
# Send message to WebSocket
self.send(text_data=json.dumps({"message": message}))
- 두 개의 세션으로 127.0.0.1:8000/chat/lobby/ 접속 시 서로 메시지 공유됨
비동기식으로 재 작성하는 코드는 튜토리얼 3참고 !
https://channels.readthedocs.io/en/stable/tutorial/part_3.html
https://www.youtube.com/watch?v=cw8-KFVXpTE
그리고 이분 유튜브도 설명 잘 나와있음 ! 참고하시면 좋을듯 !