1 – 데이터를 JSON으로 바꾸기
1.1 – 시리얼라이저 파일 만들기
- 편집기에서 새 파일을 만듭니다.
- 아래 내용을 붙여 넣습니다.
from rest_framework import serializers
from .models import Conversation, Message
class MessageSerializer(serializers.ModelSerializer):
class Meta:
model = Message
# JSON에 담을 칸을 고릅니다.
fields = ["id", "role", "content", "created_at"]
# 서버가 값을 정하는 칸이라 받는 쪽에서 고칠 수 없게 막습니다.
read_only_fields = ["id", "created_at"]
class ConversationSerializer(serializers.ModelSerializer):
# 이 방에 붙은 글을 함께 담습니다.
# source 를 적지 않아도 되는 이유는 모델에서 related_name="messages" 로 이름을 정해 뒀기 때문입니다.
messages = MessageSerializer(many=True, read_only=True)
class Meta:
model = Conversation
fields = ["id", "title", "created_at", "messages"]
read_only_fields = ["id", "created_at"]chat폴더 안에"serializers.py"라는 이름으로 저장합니다.
직렬화(serialization)는 파이썬 객체를 JSON 같은 글자 형식으로 바꾸는 일입니다. 데이터베이스에서 꺼낸 대화방은 파이썬 객체라 그대로 인터넷으로 보낼 수 없습니다. 글자로 바꿔야 보낼 수 있고, 받은 글자를 다시 파이썬 객체로 되돌려야 저장할 수 있습니다. 이 두 방향을 모두 맡는 것이 방금 만든 시리얼라이저(serializer)입니다. 짐을 부칠 때 상자에 담아 보내고 받는 쪽에서 상자를 푸는 것과 같으며, 담는 규칙과 푸는 규칙을 이 파일 한곳에 적어 둡니다.
ModelSerializer는 모델을 보고 칸 목록을 알아서 만드는 시리얼라이저입니다. 칸 하나하나를 손으로 적지 않아도 되므로 코드가 짧아집니다.
read_only_fields에 넣은 칸은 밖에서 보내온 값을 무시합니다. id와 created_at은 Django가 정하는 값이므로, 밖에서 고칠 수 있게 두면 남의 번호를 덮어쓰는 요청이 들어올 수 있습니다.
messages에 read_only=True를 준 이유는 대화방을 만들 때 글까지 한꺼번에 받지 않기 때문입니다. 글은 대화방을 만든 뒤 따로 추가합니다.
1.2 – 시리얼라이저가 도는지 확인하기
- 터미널에서
chatbot-app폴더로 이동합니다. - Django 셸을 엽니다.
python manage.py shell
- 아래 세 줄을 한 줄씩 입력합니다.
from chat.models import Conversation
from chat.serializers import ConversationSerializer
ConversationSerializer(Conversation.objects.first()).data앞서 관리자 화면에서 만든 대화방이 딕셔너리 모양으로 나타납니다. 화면을 만들기 전에 셸에서 먼저 시험하면 오류가 어느 쪽에서 났는지 가릅니다. title과 created_at이 보이고, messages 안에 넣어 둔 글이 함께 들어 있습니다. 대화방을 아직 만들지 않았다면 None이 나오므로, 관리자 화면에서 하나 만든 뒤 다시 시도합니다.
- 셸을 닫습니다.
exit()
실습 코칭 프롬프트
이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.
실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.
아래는 시리얼라이저 만들기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: Conversation 과 Message 를 JSON으로 바꾸는 시리얼라이저를 만들고, Django 셸에서 실제로 JSON이 나오는지 확인하는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- fields 목록에 적은 이름이 모델의 칸 이름과 정확히 같은지 먼저 확인해 주세요.
아래는 시리얼라이저 만들기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: Conversation 과 Message 를 JSON으로 바꾸는 시리얼라이저를 만들고, Django 셸에서 실제로 JSON이 나오는지 확인하는 것입니다.
지금까지 한 것: serializers.py 를 만들고 셸에서 ConversationSerializer 를 불러 봤습니다
막힌 지점: messages 항목이 결과에 안 나옵니다
화면에 나온 메시지: 없음
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- fields 목록에 적은 이름이 모델의 칸 이름과 정확히 같은지 먼저 확인해 주세요.
{지금까지 한 것}— 어느 단계까지 마쳤는지 적습니다. 예:django-admin startproject config . 까지 실행했습니다{막힌 지점}— 무엇을 하려다 안 됐는지 적습니다. 예:python manage.py runserver 를 실행하면 서버가 바로 꺼집니다{에러 메시지}— 화면에 나온 글을 그대로 붙여 넣습니다. 없으면없음이라고 적습니다.
AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.
2 – 주소에 기능 붙이기
2.1 – 뷰셋으로 네 동작 한 번에 만들기
- 편집기로
chat/views.py파일을 엽니다. - 파일 내용을 아래로 바꿉니다.
from rest_framework import viewsets
from .models import Conversation
from .serializers import ConversationSerializer
class ConversationViewSet(viewsets.ModelViewSet):
"""대화방을 만들고, 보고, 고치고, 지웁니다."""
# 어떤 데이터를 다룰지 정합니다. 최근에 만든 방이 위로 오게 정렬합니다.
queryset = Conversation.objects.all().order_by("-created_at")
# 그 데이터를 어떤 규칙으로 JSON으로 바꿀지 정합니다.
serializer_class = ConversationSerializer- 파일을 저장합니다.
뷰(view)는 요청을 받아 무엇을 할지 정하는 코드입니다. 뷰셋(viewset)은 목록 조회·등록·수정·삭제를 한 클래스에 묶어 둔 뷰입니다. 두 줄만 적었는데 네 동작이 모두 생깁니다. ModelViewSet이 그 동작을 미리 갖고 있고, 어떤 데이터를 어떤 규칙으로 다룰지만 채워 넣으면 되기 때문입니다.
order_by("-created_at")의 앞에 붙은 빼기 기호는 내림차순을 뜻합니다. 빼기 기호를 빼면 오래된 방이 위로 옵니다.
2.2 – 라우터로 주소 만들기
- 편집기에서 새 파일을 만듭니다.
- 아래 내용을 붙여 넣습니다.
from rest_framework.routers import DefaultRouter
from .views import ConversationViewSet
router = DefaultRouter()
# 첫 번째 값이 주소 앞부분, basename 은 Django가 내부에서 쓰는 이름입니다.
router.register("conversations", ConversationViewSet, basename="conversation")
urlpatterns = router.urlschat폴더 안에"urls.py"라는 이름으로 저장합니다.- 편집기로
config/urls.py파일을 엽니다. - 파일 내용을 아래로 바꿉니다.
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
# /api/ 로 시작하는 주소는 chat/urls.py 가 이어받습니다.
path("api/", include("chat.urls")),
]- 파일을 저장합니다.
뷰를 만들어도 주소가 없으면 밖에서 부를 수 없습니다. 라우터(router)는 뷰셋 하나를 받아 필요한 주소를 자동으로 만들어 주는 도구이며, 방금 등록한 한 줄이 아래 주소를 모두 만들어 냅니다.

같은 주소라도 요청 방식이 다르면 하는 일이 달라집니다.
주소를 두 파일에 나눠 적은 이유가 있습니다. config/urls.py는 어느 앱이 어느 앞부분을 맡을지만 정하고, 세부 주소는 각 앱이 자기 파일에 적습니다. 앱이 늘어나도 config/urls.py는 한 줄씩만 늘어납니다.
2.3 – 브라우저에서 네 동작 눌러 보기
- 서버를 켭니다.
python manage.py runserver
- 브라우저에서
http://127.0.0.1:8000/api/conversations/에 접속합니다.
Conversation List라는 제목의 회색 화면이 나타나고, 그 아래에 대화방이 JSON으로 표시됩니다. Django REST framework에는 브라우저로 API를 시험하는 화면이 들어 있어, 별도 도구 없이 눌러 볼 수 있습니다.
- 화면 맨 아래 [HTML form] 탭에서
Title칸에두 번째 대화를 입력하고 [POST]를 클릭합니다.
새 대화방이 만들어지고 목록 맨 위에 나타납니다. 이것이 등록 동작입니다.
- 주소창에
http://127.0.0.1:8000/api/conversations/1/을 입력합니다. 맨 뒤 숫자는 목록에 보이는id값 가운데 하나로 바꿉니다.
Conversation Instance 화면이 나타나고 그 방 하나만 표시됩니다. 화면 오른쪽 위에 [DELETE] 버튼이 있고, 아래 입력란에서 제목을 고쳐 [PUT]을 누르면 수정됩니다.
주소 맨 뒤 빗금(/)을 빠뜨리면 404 Not Found가 나타납니다. Django는 빗금으로 끝나는 주소를 기본으로 쓰므로, 주소를 손으로 입력할 때 빠뜨리기 쉽습니다.
이 회색 화면은 사람이 눌러 보라고 있는 것이고, React가 요청할 때는 같은 주소에서 JSON만 돌아옵니다. 화면 오른쪽 위 [json] 버튼을 누르면 React가 받는 것과 같은 모양을 볼 수 있습니다.
실습 코칭 프롬프트
이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.
실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.
아래는 뷰셋과 라우터로 API 주소 만들기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: ModelViewSet 으로 대화방의 등록·조회·수정·삭제를 만들고, 라우터로 /api/conversations/ 주소를 여는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 주소 맨 뒤 빗금이 빠지지 않았는지, config/urls.py 에 include 를 넣었는지 먼저 확인해 주세요.
아래는 뷰셋과 라우터로 API 주소 만들기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: ModelViewSet 으로 대화방의 등록·조회·수정·삭제를 만들고, 라우터로 /api/conversations/ 주소를 여는 것입니다.
지금까지 한 것: views.py 에 ConversationViewSet 을 만들고 chat/urls.py 에 라우터를 등록했습니다
막힌 지점: /api/conversations/ 로 들어가면 페이지를 못 찾습니다
화면에 나온 메시지: 404 Not Found
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 주소 맨 뒤 빗금이 빠지지 않았는지, config/urls.py 에 include 를 넣었는지 먼저 확인해 주세요.
{지금까지 한 것}— 어느 단계까지 마쳤는지 적습니다. 예:django-admin startproject config . 까지 실행했습니다{막힌 지점}— 무엇을 하려다 안 됐는지 적습니다. 예:python manage.py runserver 를 실행하면 서버가 바로 꺼집니다{에러 메시지}— 화면에 나온 글을 그대로 붙여 넣습니다. 없으면없음이라고 적습니다.
AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.
3 – 대화방 안의 글 다루기
3.1 – 글을 등록하는 자리 만들기
- 편집기로
chat/views.py파일을 엽니다. - 파일 맨 위 불러오기 줄을 아래로 바꿉니다.
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from .models import Conversation
from .serializers import ConversationSerializer, MessageSerializerConversationViewSet클래스 안,serializer_class줄 아래에 아래 내용을 이어 적습니다.
# detail=True : 대화방 하나를 지목하는 주소에 붙습니다.
# methods=["post"] : 보내는 동작만 받습니다.
# 만들어지는 주소 → /api/conversations/1/messages/
@action(detail=True, methods=["post"])
def messages(self, request, pk=None):
# 주소에 적힌 번호로 대화방을 찾습니다. 없으면 404를 돌려줍니다.
conversation = self.get_object()
serializer = MessageSerializer(data=request.data)
# raise_exception=True : 값이 규칙에 안 맞으면 400과 함께 이유를 돌려줍니다.
serializer.is_valid(raise_exception=True)
# 어느 방에 속하는지는 주소에서 정해지므로 여기서 채웁니다.
serializer.save(conversation=conversation)
return Response(serializer.data, status=status.HTTP_201_CREATED)- 파일을 저장합니다.
대화방 안에 글을 넣는 동작은 앞의 뷰셋에 들어 있지 않습니다. 글은 대화방에 딸린 데이터라 어느 방에 넣을지 함께 받아야 하기 때문입니다.
@action은 뷰셋에 동작을 하나 더 붙이는 표시입니다. 이 표시를 붙이면 라우터가 그 동작에 맞는 주소까지 함께 만듭니다. 그래서 urls.py는 고치지 않아도 됩니다.
serializer.save(conversation=conversation)에서 방을 코드로 채우는 이유가 있습니다. 밖에서 보낸 값으로 방을 정하게 두면 남의 대화방에 글을 넣는 요청이 통과합니다. 주소에 적힌 방으로만 저장하면 그 일이 일어나지 않습니다.
3.2 – 글 등록이 되는지 확인하기
- 브라우저에서
http://127.0.0.1:8000/api/conversations/1/messages/에 접속합니다. 맨 앞 숫자는 실제 대화방id로 바꿉니다.
Messages 화면이 나타납니다. 이 주소는 보내는 동작만 받으므로 목록은 표시되지 않습니다.
- 아래 [HTML form] 탭에서
Role은사람을 고르고,Content에안녕하세요를 입력한 뒤 [POST]를 클릭합니다.
HTTP 201 Created라는 줄과 함께 방금 넣은 글이 JSON으로 표시됩니다. 201은 새로 만들어졌다는 뜻의 응답 번호입니다.
http://127.0.0.1:8000/api/conversations/1/로 돌아갑니다.
messages 항목 안에 방금 넣은 글이 들어 있습니다. 대화방을 하나 조회하면 그 안의 글까지 함께 오는 구조입니다. 화면 쪽에서는 요청을 한 번만 보내면 대화 내용을 모두 받을 수 있습니다.
Role에 목록에 없는 값을 넣으면 400 Bad Request와 함께 "is not a valid choice"라는 문장이 돌아옵니다. 모델에서 choices로 값을 묶어 둔 것이 여기서 걸러 주는 것입니다.
실습 코칭 프롬프트
이 부분을 혼자 해 보다 막히면 아래 프롬프트를 대화형 AI(ChatGPT·Claude·Gemini)에 붙여 넣어 한 단계씩 도움받습니다.
실습에 쓰던 대화창이 아니라 새 대화창에 붙여 넣습니다. 실습 대화창에는 앞서 시킨 다른 지시가 남아 있어, 그 위에 얹으면 답이 뒤섞입니다.
아래는 대화방 안에 글 등록하기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: @action 을 붙여 /api/conversations/1/messages/ 주소를 만들고, 그 방에 글을 저장하는 것입니다.
지금까지 한 것: {지금까지 한 것}
막힌 지점: {막힌 지점}
화면에 나온 메시지: {에러 메시지}
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 글을 저장할 때 어느 대화방에 속하는지를 코드에서 채우고 있는지 먼저 확인해 주세요.
아래는 대화방 안에 글 등록하기 실습을 혼자 해 보다 막혀서 도움을 받으려는 요청입니다.
지금 하려는 것: @action 을 붙여 /api/conversations/1/messages/ 주소를 만들고, 그 방에 글을 저장하는 것입니다.
지금까지 한 것: views.py 에 @action 으로 messages 함수를 붙였습니다
막힌 지점: POST 를 누르면 저장이 안 됩니다
화면에 나온 메시지: {"conversation": ["This field is required."]}
다음 규칙을 지켜 주세요.
- 정답 코드를 통째로 주지 마세요. 다음 한 단계만 알려 주세요.
- 먼저 왜 막혔는지 짚어 주고, 제가 직접 해 보게 하세요.
- 제가 해 본 결과를 말하면 그때 확인 질문을 던지고 다음 단계로 넘어가세요.
- 제가 놓치기 쉬운 부분이 보이면 마지막에 한 줄로 짚어 주세요.
- 글을 저장할 때 어느 대화방에 속하는지를 코드에서 채우고 있는지 먼저 확인해 주세요.
{지금까지 한 것}— 어느 단계까지 마쳤는지 적습니다. 예:django-admin startproject config . 까지 실행했습니다{막힌 지점}— 무엇을 하려다 안 됐는지 적습니다. 예:python manage.py runserver 를 실행하면 서버가 바로 꺼집니다{에러 메시지}— 화면에 나온 글을 그대로 붙여 넣습니다. 없으면없음이라고 적습니다.
AI가 고친 코드 전체를 한 번에 내놓으면 “코드 전체 말고 어느 줄을 왜 고쳐야 하는지 한 단계만 알려 주세요”라고 되물으십시오. 에러 메시지를 요약해 적으면 원인을 못 짚습니다. 화면에 나온 글을 그대로 붙여 넣습니다.