바뀜

1,097 바이트 추가됨 ,  2022년 10월 17일 (월) 14:45
편집 요약 없음
1번째 줄: 1번째 줄:  
== 개요 ==
 
== 개요 ==
 +
장고 채널 기능의 활용을 위해 간단한 채팅 앱 만들어보기.
   −
== 기초준비 ==
+
=== 사전 준비 ===
 +
{| class="wikitable"
 +
!과정
 +
!설명
 +
!방법
 +
|-
 +
|장고
 +
|장고가 설치되어 있다고 가정한다.
 +
|[http://id8436.iptime.org:2786/mediawiki/index.php/1.%20%EC%9E%A5%EA%B3%A0%20%EA%B0%9C%EC%9A%94 1. 장고 개요]
 +
|-
 +
|채널 설치
 +
|채널이 설치되어 있다고 가정한다.
 +
|[http://id8436.iptime.org:2786/mediawiki/index.php/%EC%9E%A5%EA%B3%A0%20channels 장고 channels]
 +
|}
 +
= 기초준비 =
   −
=== 채팅어플 만들기 ===
+
== 채팅어플 만들기 ==
 
패키지설치부터 진행하기엔 중간점검이 어려워 틀 만들기를 먼저 수행한다.
 
패키지설치부터 진행하기엔 중간점검이 어려워 틀 만들기를 먼저 수행한다.
 
{| class="wikitable"
 
{| class="wikitable"
12번째 줄: 27번째 줄:  
|어플리케이션생성
 
|어플리케이션생성
 
|채팅을 위한 앱을 생성한다.
 
|채팅을 위한 앱을 생성한다.
앱을 생성하고 __init__.py와 views.py를 제외한 모든 것들을 지운다.
   
|django-admin startapp chat
 
|django-admin startapp chat
 
|-
 
|-
19번째 줄: 33번째 줄:  
|<syntaxhighlight lang="python">
 
|<syntaxhighlight lang="python">
 
INSTALLED_APPS = [
 
INSTALLED_APPS = [
 +
    ...
 
     'chat',
 
     'chat',
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|-
 
|-
|URL매핑
+
|폴더 정리
|기본이 되는 urls.py 안에서 해당 앱으로 매핑을 시켜준다.
+
| - 앱을 생성하고 생성된 __init__.py와 views.py를 제외한 모든 것들을 지운다.
|path('chat/', include('chat.urls')),
+
(채팅기능만을 위해선 나머지는 필요 없어, 지워도 된다. 근데 그냥 두자.)
 +
 
 +
- 탬플릿을 담기 위해 templates/chat 디렉토리를 생성해준다.
 +
|
 
|-
 
|-
|URL매핑2
+
|urls.py 생성 및 매핑
|그리고 안의 urls.py 작성.
+
|앱 내에서 사용되는 url을 다루기 위해 urls.py를 생성한다.
|<syntaxhighlight lang="python">
+
|urls.py의 내용.<syntaxhighlight lang="python">
from dfango.urls import path
+
from django.urls import path
 
from . import views
 
from . import views
 +
app_name = 'chat'  # 보통 앱이름을 써서 url을 구분하지만,
 +
 +
urlpatterns = [
 +
    path('', views.index, name='index'),
 +
]
 +
</syntaxhighlight>기초 urls.py 수정<syntaxhighlight lang="python">
 +
from django.contrib import admin
 +
from django.urls import include, path
    
urlpatterns = [
 
urlpatterns = [
     path('/', views.index, name='index'),
+
     path('chat/', include('chat.urls')),
 +
    path('admin/', admin.site.urls),
 
]
 
]
 
</syntaxhighlight>
 
</syntaxhighlight>
|-
+
|}
|view 작성
+
여기까지 하고 runserver 후 제대로 작동하는지 확인하자.
|
  −
|<syntaxhighlight lang="python">
  −
from django.shortcuts import render
     −
def index(request):
+
== 채팅룸 구현 ==
    return render(request, 'chat/index.html', {})
+
=== 채팅 인덱스 구현 ===
</syntaxhighlight>
+
들어갈 채팅룸을 입력하는 공간.
 +
{| class="wikitable"
 +
!과정
 +
!설명
 +
!방법
 
|-
 
|-
|탬플릿 준비
+
|채팅 인덱스 탬플릿 작성
|앱 하위에 templates>chat 디렉터리까지 만든다.
+
|채팅룸을 입력하기 위한 인덱스 탬플릿.
index.html 이라는 이름으로 만들자.
+
templates/chat/index.html로 작성하자.
 
|<syntaxhighlight lang="html+django">
 
|<syntaxhighlight lang="html+django">
<!-- chat/templates/chat/index.html -->
   
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html>
 
<html>
57번째 줄: 84번째 줄:  
     <title>Chat Rooms</title>
 
     <title>Chat Rooms</title>
 
</head>
 
</head>
 +
<body>
 +
    What chat room would you like to enter?<br>
 +
    <input id="room-name-input" type="text" size="100"><br>
 +
    <input id="room-name-submit" type="button" value="Enter">
   −
<body>
  −
    What chat room would you like to enter?<br/>
  −
    <input id="room-name-input" type="text" size="100"/><br/>
  −
    <input id="room-name-submit" type="button" value="Enter"/>
  −
   
   
     <script>
 
     <script>
 
         document.querySelector('#room-name-input').focus();
 
         document.querySelector('#room-name-input').focus();
78번째 줄: 104번째 줄:  
</body>
 
</body>
 
</html>
 
</html>
 +
</syntaxhighlight>
 +
|-
 +
|뷰 작성
 +
|
 +
|<syntaxhighlight lang="python">
 +
from django.shortcuts import render
 +
 +
def index(request):
 +
    return render(request, 'chat/index.html')
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|}
 
|}
여기까지 하고 runserver 후 제대로 작동하는지 확인하자.
      
=== 채팅룸 구현 ===
 
=== 채팅룸 구현 ===
87번째 줄: 121번째 줄:  
!설명
 
!설명
 
!방법
 
!방법
|-
  −
|URL매핑
  −
|앱 내의 urls.py에 추가.
  −
|<syntaxhighlight lang="python">
  −
urlpatterns = [
  −
    ...
  −
    path('<str:room_name>/', views.room, name='room'),
  −
    ...
  −
]
  −
</syntaxhighlight>
  −
|-
  −
|뷰 작성
  −
|room 뷰 작성
  −
mark_safe와 json을 가져온다.
  −
|<syntaxhighlight lang="python">
  −
from django.shortcuts import render
  −
from django.utils.safestring import mark_safe
  −
import json
  −
  −
def room(request, room_name):
  −
    return render(request, 'chat/room.html', {
  −
        'room_name_json': mark_safe(json.dumps(room_name))
  −
    })
  −
</syntaxhighlight>
   
|-
 
|-
 
|탬플릿 작성
 
|탬플릿 작성
|/char/room.html을 만든다.
+
|templates/chat/room.html
 
|<syntaxhighlight lang="html+django">
 
|<syntaxhighlight lang="html+django">
 
<!DOCTYPE html>
 
<!DOCTYPE html>
121번째 줄: 131번째 줄:  
     <title>Chat Room</title>
 
     <title>Chat Room</title>
 
</head>
 
</head>
   
<body>
 
<body>
     <textarea id="chat-log" cols="100" rows="20"></textarea><br/>
+
     <textarea id="chat-log" cols="100" rows="20"></textarea><br>
     <input id="chat-message-input" type="text" size="100"/><br/>
+
     <input id="chat-message-input" type="text" size="100"><br>
     <input id="chat-message-submit" type="button" value="Send"/>
+
     <input id="chat-message-submit" type="button" value="Send">
</body>
+
    {{ room_name|json_script:"room-name" }}
 +
    <script>
 +
        const roomName = JSON.parse(document.getElementById('room-name').textContent);
   −
<script>
+
        const chatSocket = new WebSocket(
    var roomName = {{ room_name_json }};
+
            'ws://'
 +
            + window.location.host
 +
            + '/ws/chat/'
 +
            + roomName
 +
            + '/'
 +
        );
   −
    var chatSocket = new WebSocket(
+
        chatSocket.onmessage = function(e) {
        'ws://' + window.location.host +
+
            const data = JSON.parse(e.data);
        '/ws/chat/' + roomName + '/');
+
            document.querySelector('#chat-log').value += (data.message + '\n');
 +
        };
   −
    chatSocket.onmessage = function(e) {
+
        chatSocket.onclose = function(e) {
        var data = JSON.parse(e.data);
+
            console.error('Chat socket closed unexpectedly');
        var message = data['message'];
+
         };
         document.querySelector('#chat-log').value += (message + '\n');
  −
    };
     −
    chatSocket.onclose = function(e) {
+
         document.querySelector('#chat-message-input').focus();
         console.error('Chat socket closed unexpectedly');
+
        document.querySelector('#chat-message-input').onkeyup = function(e) {
    };
+
            if (e.keyCode === 13) {  // enter, return
 
+
                document.querySelector('#chat-message-submit').click();
    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) {
  −
        var messageInputDom = document.querySelector('#chat-message-input');
  −
        var message = messageInputDom.value;
  −
        chatSocket.send(JSON.stringify({
  −
             'message': message
  −
        }));
  −
 
  −
         messageInputDom.value = '';
  −
    };
  −
</script>
      +
        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>
 
</html>
 +
</syntaxhighlight>
 +
|-
 +
|뷰 작성
 +
|뷰에 다음 함수를 추가한다.
 +
|<syntaxhighlight lang="python">
 +
def room(request, room_name):
 +
    return render(request, 'chat/room.html', {
 +
        'room_name': room_name
 +
    })
 +
</syntaxhighlight>
 +
|-
 +
|URL
 +
|다음의 내용을 urls.py에 추가한다.
 +
|<syntaxhighlight lang="python">
 +
path('<str:room_name>/', views.room, name='room'),
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|}
 
|}
   
=== 참가자 구현 ===
 
=== 참가자 구현 ===
 
{| class="wikitable"
 
{| class="wikitable"
179번째 줄: 203번째 줄:  
클라이언트로부터 메시지를 받아서 그대로 전달.
 
클라이언트로부터 메시지를 받아서 그대로 전달.
 
|<syntaxhighlight lang="python">
 
|<syntaxhighlight lang="python">
 +
import json
 
from channels.generic.websocket import WebsocketConsumer
 
from channels.generic.websocket import WebsocketConsumer
import json
      
class ChatConsumer(WebsocketConsumer):
 
class ChatConsumer(WebsocketConsumer):
228번째 줄: 252번째 줄:  
})
 
})
 
</syntaxhighlight>
 
</syntaxhighlight>
|}
+
|}여기까지 하고 채팅을 쳐 보면... 채팅이 나와야 정상.
여기까지 하고 채팅을 쳐 보면... 채팅이 나와야 정상.
+
 
    
=== 체널레이어 구현 ===
 
=== 체널레이어 구현 ===
255번째 줄: 279번째 줄:  
</syntaxhighlight>
 
</syntaxhighlight>
 
|}
 
|}
 +
 +
 
== 개요 ==
 
== 개요 ==
 
레디스 서버를 이용한 실시간 채팅 구현
 
레디스 서버를 이용한 실시간 채팅 구현