[Django] Channels 사용하기 - 1

2022. 10. 17. 16:55TIL/Django

Django의 Chaanels는 Django에서 웹 소켓을 사용할 수 있게 해주는 라이브러리이다.

Channels는 django에서 HTTP이외의 웹 소켓이나, IoT 프로토콜과 같은 다양한 프로토콜을 지원하기 위해 만들어졌다.

Channels는 비동기 형식으로 django를 래핑하여 작동한다. ASGI 기반으로 개발 되었다.

하기 내용은 Channels 공식 문서를 참조하여 작성하는 글이다.

설치

$ python3 -m pip install -U channels

참고로 필자는 위의 방법으로 설치 시 에러가 나서 아래와 같이 설치했다.

$ pip install channels

설치가 완료되면 다음과 같이 확인해 보자.

$ python3 -c 'import channels; print(channels.__version__)'

-c 옵션은 cat의 줄임말 같다. arg로 들어오는 cmd를 쉘 상에 출력하라는 뜻 인듯...

django project 생성

django project를 생성해 준다.

$ django-admin startproject socket_channels

socket_test directory에는 다음과 같이 생성되었을 것이다.

socket_test/
    manage.py
    socket_channels/
        __init__.py
        asgi.py
        settings.py
        urls.py
        wsgi.py

그 다음, chat 기능을 이용하기 위한 chat application을 만들자

$ python3 manage.py startapp chat

그러면 chat directory가 생성되고 그 안에 다음과 같이 구조가 나올 것이다.

chat/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

여기서 __init__.pyviews.py를 제외하고는 여기서는 필요 없으므로 일단 삭제한다.

$ rm admin.py apps.py models.py tests.py
$ rm -rf migrations/

그리고 나서, socket_channels/settings.py 파일의 INSTALLED_APPSchat 앱을 추가해 준다.

# socket_channels/settings.py
INSTALLED_APPS = [
    'chat',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

index view 추가

첫번째 view를 추가할 것인데, 채팅방 이름을 정하는 view이다. 다음과 같이 폴더를 생성하고 그 안에 index.html 파일을 추가하자

chat/
    __init__.py
    templates/
        chat/
            index.html
    views.py

index.html 파일에는 채팅방 이름을 설정하는 html 코드를 입력하자.

<!-- chat/templates/chat/index.html -->
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Chat Rooms</title>
</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">

    <script>
        document.querySelector('#room-name-input').focus();
        document.querySelector('#room-name-input').onkeyup = function(e) {
            if (e.keyCode === 13) {  // enter, return
                document.querySelector('#room-name-submit').click();
            }
        };

        document.querySelector('#room-name-submit').onclick = function(e) {
            var roomName = document.querySelector('#room-name-input').value;
            window.location.pathname = '/chat/' + roomName + '/';
        };
    </script>
</body>
</html>

이제 해당 html 파일을 띄워줄 view를 작성하자

# chat/views.py
from django.shortcuts import render


def index(request):
    return render(request, "chat/index.html")

이제 view를 호출할 URL을 view와 매핑해야 한다. 따라서 URLconf를 작성하자.

chat directory에 urls.py 파일을 만들고 다음과 같이 작성하자.

chat/
    __init__.py
    templates/
        chat/
            index.html
    urls.py
    views.py

urls.py에는 다음과 같이 작성하면 된다.

# chat/urls.py
from django.urls import path

from . import views


urlpatterns = [
    path("", views.index, name="index"),
]

위의 urls.pychat앱에 대한 url이다. 우리의 프로젝트는 socket_channels(공식 문서 상에는 mysite)이므로 root url이 필요하다.

socket_channels/urls.py에다가 다음과 같이 추가하자(이 urls.py는 django project를 생성할 때 이미 존재하는 파일이다.)

# mysite/urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("chat/", include("chat.urls")), # 이 부분 추가. localhost:8000/chat/ 으로 호출이 되면 chat.urls 파일로 가라는 뜻
    path("admin/", admin.site.urls),
]

이제 서버를 실행해 보자.

$ python3 manage.py runserver

아무 브라우저에 접속하여 주소창에 http://127.0.0.1:8000/chat/을 입력하면

이렇게 입력하는 창이 뜬다.

여기에 "lobby"라는 채팅방 이름을 입력하고 Enter를 누르면 "Page not found" 에러가 날 것이다. 당연한 이야기이다. "lobby"로 검색했을 때 나오는 채팅방이 아직은 존재하지 않기 때문. 후에 채팅방을 연결하도록 해보자.

이 튜토리얼에서는 Database를 사용하지 않기 때문에 runserver를 했을 때 나오는 migration warning은 무시해도 된다.

Channels 라이브러리 사용하기

아직까지는 그저 regular Django app만 사용했기 때문에 Channels를 쓰지 않았다. 이제 Channels의 기능을 살펴보자.

Channels에 대한 라우팅 구성을 먼저 보자. Channels 라우팅 구성은 채널 서버에서 HTTP 요청을 수신할 때 실행할 코드를 채널에 넘겨준다는 점이 Django URLconf와 유사한 ASGI application이다.

아래 코드를 살펴보며 더 정확하게 알아보자.

# socket_channels/asgi.py
import os

from channels.routing import ProtocolTypeRouter
from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "socket_channels.settings")

application = ProtocolTypeRouter(
    {
        "http": get_asgi_application(),
        # Just HTTP for now. (We can add other protocols later.)
        # 지금은 HTTP 프로토콜로 설정했지만, 후에 socket통신을 할 예정이므로 다른 프로토콜을 추가할 것이다.
    }
)

위 설정은 django의 asgi application에게 어떤 프로토콜을 사용할 것인지 알려주는 설정이다. 이 부분은 후에 좀 더 자세하게 살펴보자!

이제 Daphne 라이브러리를 INSTALLED_APPS에 추가하자.

# socket_channels/settings.py
INSTALLED_APPS = [
    'daphne',
    'chat',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

또한 root 라우팅 구성에서 Daphne를 실행할 수 있게 위치를 알려주어야 한다.

socket_channels/settings.py에 다음을 추가하자.

# socket_channels/settings.py
# Daphne
ASGI_APPLICATION = "socket_channels.asgi.application"

다른 third-party app들에 의해 daphne가 덮여 쓰여질 수 있으니 INSTALLED_APPS의 가장 상단에 위치시켰는지 확인해야 한다.

이제 서버를 실행해 보자.

$ python3 manage.py runserver

사진을 보면 기존에 Starting development server at http://127.0.0.1:8000/ 라고 되어있던 부분이 Starting ASGI/Daphne version 4.0.0 development server at http://127.0.0.1:8000/ 로 바뀌어 있는 것을 확인할 수 있다.

이것은 Daphne 개발 서버로 실행되고 있다는 것을 알 수 있다.

공식 문서에서는 "Notice the line beginning with Starting ASGI/Daphne …. This indicates that the Daphne development server has taken over from the Django development server." 라고 표현하고 있다. 이를 직역하면 "Daphne development 서버가 Django development 서버를 인수했다." 이다.


Tutorial 2에서 계속...

반응형

'TIL > Django' 카테고리의 다른 글

[Django] Channels 사용하기 - 3  (0) 2022.10.24
[Django] Channels 사용하기 - 2  (2) 2022.10.18
[Django] connection.queries always empty  (0) 2022.10.13
[Django] DRF란?  (0) 2022.10.12
[Django] pending되는 이슈에 대한 고찰  (0) 2022.08.02