ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [5월 1주차-5/7]🧩 Django로 RESTful API 만들기 & 실시간 채팅 앱 구축 (Channels 활용)
    Why Not SW CAMP 5기/수업 기록 2025. 5. 7. 13:48

    ✅ 1. RESTful API란?

    RESTful API는 웹에서 클라이언트와 서버가 HTTP를 통해 통신할 수 있도록 만든 규칙 기반 구조입니다.
    GET, POST, PUT, DELETE 같은 HTTP 메서드로 자원을 주고받으며, 각 요청은 독립적이고 일관된 URL 구조를 가집니다.

    📌 핵심 개념 정리

    1. 리소스(Resource): /users/, /posts/3처럼 명사로 된 URL 사용
    2. HTTP 메서드:
      • GET: 조회
      • POST: 생성
      • PUT / PATCH: 수정
      • DELETE: 삭제
    3. 무상태성(Stateless): 요청은 서로 독립적이며, 서버는 이전 요청 상태를 기억하지 않음
    4. 표현(Representation): JSON 등을 통해 데이터 표현
    5. 일관된 URI 구조:
      • /users → 전체 사용자
      • /users/1/posts → 특정 사용자의 게시글

    🛠 2. Django + DRF로 REST API 만들기

    🔧 프로젝트 및 앱 생성

    python -m venv env/rest
    .\env\Scripts\activate
    
    pip install django djangorestframework
    
    django-admin startproject rest
    cd rest
    python manage.py startapp restapp
    

    settings.py 수정:

    INSTALLED_APPS = [
        ...
        'rest_framework',
        'restapp',
    ]
    

    📄 모델 작성 (restapp/models.py)

    from django.db import models
    from django.contrib.auth.models import User
    
    class Post(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()
        author = models.ForeignKey(User, on_delete=models.CASCADE)
        created_at = models.DateTimeField(auto_now_add=True)
        update_at = models.DateTimeField(auto_now=True)
    
        class Meta:
            ordering = ['-created_at']
    
        def __str__(self):
            return self.title
    

    📦 시리얼라이저 작성 (restapp/serializers.py)

    from rest_framework import serializers
    from .models import Post
    
    class PostSerializer(serializers.ModelSerializer):
        class Meta:
            model = Post
            fields = '__all__'
    

    🧠 API View 작성 (restapp/views.py)

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from .models import Post
    from .serializers import PostSerializer
    
    class PostListCreateAPIView(APIView):
        def get(self, request):
            queryset = Post.objects.all()
            serializer = PostSerializer(queryset, many=True)
            return Response(serializer.data)
    
        def post(self, request):
            serializer = PostSerializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    

    🌐 URL 설정

    restapp/urls.py

    from django.urls import path
    from .views import PostListCreateAPIView
    
    urlpatterns = [
        path('restapp/', PostListCreateAPIView.as_view(), name='restapp-list-create'),
    ]
    

    rest/urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('restapp.urls')),
    ]
    

    🚀 마이그레이션 및 실행

    python manage.py makemigrations
    python manage.py migrate
    python manage.py runserver
    

    http://127.0.0.1:8000/api/restapp/ 로 접속해서 API 확인!


     

     

    💬 3. Django Channels + WebSocket으로 채팅 앱 만들기

    📦 의존성 설치

    pip install channels channels_redis redis daphne
    

    settings.py

    INSTALLED_APPS = [
        'daphne',
        'channels',
        'chat',
        ...
    ]
    
    ASGI_APPLICATION = 'chatting.asgi.application'
    
    CHANNEL_LAYERS = {
        'default': {
            'BACKEND': 'channels_redis.core.RedisChannelLayer',
            'CONFIG': {
                "hosts": [('127.0.0.1', 6379)],
            },
        },
    }
    

    ⚙️ asgi.py 설정

    import os
    from django.core.asgi import get_asgi_application
    from channels.routing import ProtocolTypeRouter, URLRouter
    from channels.auth import AuthMiddlewareStack
    from chat import routing as chat_routing
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'chatting.settings')
    
    django_asgi_app = get_asgi_application()
    
    application = ProtocolTypeRouter({
        "http": django_asgi_app,
        "websocket": AuthMiddlewareStack(
            URLRouter(
                chat_routing.websocket_urlpatterns
            )
        ),
    })
    

    🧱 모델 (chat/models.py)

    from django.db import models
    from django.contrib.auth.models import User
    
    class Room(models.Model):
        name = models.CharField(max_length=255, unique=True)
    
        def __str__(self):
            return self.name
    
    class Message(models.Model):
        room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='messages')
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        timestamp = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            ordering = ('timestamp',)
    
        def __str__(self):
            return f'{self.user.username}: {self.content[:50]}...'
    
    python manage.py makemigrations chat
    python manage.py migrate
    

    🧠 consumers.py

    from channels.generic.websocket import AsyncWebsocketConsumer
    import json
    
    class ChatConsumer(AsyncWebsocketConsumer):
        async def connect(self):
            self.room_name = self.scope['url_route']['kwargs']['room_name']
            self.room_group_name = f'chat_{self.room_name}'
            self.user = self.scope['user']
            await self.channel_layer.group_add(self.room_group_name, self.channel_name)
            await self.accept()
    
        async def disconnect(self, close_code):
            await self.channel_layer.group_discard(self.room_group_name, self.channel_name)
    
        async def receive(self, text_data):
            data = json.loads(text_data)
            message = data['message']
            await self.channel_layer.group_send(self.room_group_name, {
                'type': 'chat_message',
                'message': message,
                'user': self.user.username if self.user.is_authenticated else 'Anonymous',
                'timestamp': 'now'
            })
    
        async def chat_message(self, event):
            await self.send(text_data=json.dumps({
                'message': event['message'],
                'user': event['user'],
                'timestamp': event['timestamp']
            }))
    

    🌐 routing.py

    from django.urls import path
    from . import consumers
    
    websocket_urlpatterns = [
        path('ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
    ]
    

    💡 views.py (채팅방 접속용)

    from django.shortcuts import render, get_object_or_404
    from .models import Room
    
    def room(request, room_name):
        room_obj = get_object_or_404(Room, name=room_name)
        return render(request, 'chat/room.html', {
            'room_name': room_name,
            'room': room_obj,
            'user': request.user
        })
    

    💬 room.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Chat Room: {{ room_name }}</title>
    </head>
    <body>
    <h1>Chat Room: {{ room_name }}</h1>
    <div id="chat-log"></div>
    <input id="chat-message-input" type="text">
    <input id="chat-message-submit" type="button" value="Send">
    
    {{ room_name|json_script:"room-name" }}
    {{ user.username|json_script:"user-name" }}
    
    <script>
        const roomName = JSON.parse(document.getElementById('room-name').textContent);
        const userName = JSON.parse(document.getElementById('user-name').textContent);
        const chatSocket = new WebSocket('ws://' + window.location.host + '/ws/chat/' + roomName + '/');
    
        chatSocket.onmessage = function(e) {
            const data = JSON.parse(e.data);
            const message = data.message;
            const user = data.user;
            const timestamp = data.timestamp;
            const chatLog = document.querySelector('#chat-log');
            chatLog.innerHTML += `<b>${user}</b>: ${message}<br>`;
        };
    
        document.querySelector('#chat-message-submit').onclick = function(e) {
            const input = document.querySelector('#chat-message-input');
            const message = input.value;
            chatSocket.send(JSON.stringify({'message': message}));
            input.value = '';
        };
    </script>
    </body>
    </html>
    

    ✅ 마무리

    • Django로 RESTful API와 WebSocket 채팅을 모두 경험
    • Channels + Redis로 실시간 처리도 가능하게 됨
    • REST API → 기본 HTTP 처리,
      WebSocket → 양방향 실시간 통신

     

Designed by Tistory.