HTTP 메서드
HTTP는 요청 메서드를 정의해, 주어진 리소스(데이터)에 수행하길 원하는 행동을 뜻한다.
- GET: 특정 리소스의 조회를 의미, 이 요청은 데이터를 받기만 한다.
- POST: 특정 리소스에 엔티티를 제출할 때 쓰임, 즉 새로운 데이터를 생성할 때 쓰임
- PUT: 특정 목적 리소스의 데이터를 수정한다.
- DELETE: 특정 리소스를 삭제한다.
Django API로 GET 구현
django로 view를 구현할 때(뷰(views)와 템플릿(templates)), 질문 리스트를 보여주던 페이지가 있었다. 바로 index에 해당하는 메인 페이지다. 잠깐 기억을 되돌려 polls의 views.py를 살펴보자.
# mysite/polls/views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Question
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Choice
from django.db.models import F
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return render(request, 'polls/index.html', {
'latest_question_list': latest_question_list,
})
index는 최근 질문 5개를 리스트 형태로 템플릿에 담아 보여주는 역할을 했다. 이번에는 API로 이 index와 같은 기능을 구현해보려고 한다.
정보를 가져오는 개념이다. 우리가 HTTP 통신을 통해 요청을 보내면 해당 URL에 맞는 응답을 해줬던 방식을 GET이라고 배웠다. django에서도 그 GET 메서드를 이용하면, 리스트를 요청했을 때 해당 조건에 맞는 응답을 해줄 수 있다.
polls_api/views.py에 들어가 아래와 같이 코드를 작성해보자.
from django.shortcuts import render
from rest_framework import api_view
from rest_framework.response import Response
from polls.models import Question
from .serializers import QuestionSerializer
@api_view(['GET'])
def question_list(request):
questions = Question.objects.all()
# 여러개의 데이터를 직렬화할 때는 many=True를 사용
serializer = QuestionSerializer(questions, many=True)
return Response(serializer.data)
API의 GET 메서드를 구현하기 위해서는 api_view라는 함수를 먼저 임포트해 데코레이터로 사용할 수 있도록 해야한다. 그 다음 question 모델에서 레코드들을 모두 불러온 뒤, serializer에 담아 응답을 반환한다.
여기서 응답하는 Response()는 HTTP 응답 형태로 전송되며, 그 안에 담긴 serializer.data는 JSON 형태로 전달된다.
views.py와 함께 동반되어야 하는 것이 있다. 바로 urls.py를 수정해주어야 한다. (없을 경우 파일 생성)
mysite/polls_api/urls.py
from django.urls import path
from .views import *
app_name = 'polls_api'
urlpatterns = [
path('question/', question_list, name='question_list'),
]
또한 프로젝트 전체의 urls.py에서도 해당 앱(polls_api)의 URL을 추가해주어야 한다.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
# polls_api URL 추가
path('polls_api/', include('polls_api.urls')),
]
그 다음 서버를 실행해 해당 URL('/polls_api/question')에 접속해보자.
따로 구현하지 않은 웹 페이지이지만, 이전에 만들었던 질문들의 리스트가 보여지고 있다. REST API 형태로 GET 요청을 보냈을 때, 위와 같은 응답이 나타난다는 걸 알 수 있다.
우측 상단의 GET 버튼을 눌러 json을 선택하면 shell에서 .objects.all() 메서드를 사용했을 때처럼 원본이 나타난다.
[{"id":1,"question_text":"가장 추천하는 가을 캠핑장은 어디인가요?","pub_date":"2024-10-07T04:20:27Z"},{"id":2,"question_text":"야구 vs 축구","pub_date":"2024-10-07T05:17:05.082114Z"},{"id":3,"question_text":"abc???","pub_date":"2024-10-07T05:27:29.992184Z"},{"id":4,"question_text":"야구를 왜 좋아하시나요?","pub_date":"2024-10-07T07:28:39.876305Z"},{"id":5,"question_text":"new_question","pub_date":"2024-10-08T04:34:08.922218Z"},{"id":6,"question_text":"제목수정","pub_date":"2024-10-10T02:25:09.096995Z"},{"id":7,"question_text":"모델 시리얼라이저로 생성","pub_date":"2024-10-10T04:20:19.022404Z"}]
POST(데이터 생성)
이번에는 데이터 생성을 의미하는 POST 요청을 구현해보자.
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from polls.models import Question
from .serializers import QuestionSerializer
@api_view(['GET', 'POST'])
def question_list(request):
if request.method == 'GET':
questions = Question.objects.all()
# 여러개의 데이터를 직렬화할 때는 many=True를 사용
serializer = QuestionSerializer(questions, many=True)
return Response(serializer.data)
# POST 요청 처리
elif request.method == 'POST':
serializer = QuestionSerializer(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)
데코레이터 하나를 통해 여러가지를 활용하기 위해 요청에 따라 동작을 수행하도록 if문을 추가했다.
'POST' 요청의 경우 생성할 데이터를 serializer에 담은 후 is_valid()를 통해 유효성 검사가 통과된 것만 저장한 뒤 201 상태코드를 반환한다. 만약 유효하지 않는 데이터라면 400 에러 코드를 반환하도록 했다.
코드를 작성하고 위에서 봤던 GET 요청 페이지를 새로고침하면, POST가 Allow 목록에 표시된 것을 확인할 수 있다.
그리고 화면 하단에 위와 같은 폼이 하나 생기는데, 이를 통해 POST 요청을 진행할 수 있다. 이 창에 양식을 맞춘 뒤 POST 요청을 눌러보면,
위와 같이 개발자 도구에서 관련 내용을 확인할 수 있다. Request method는 POST이며, 201 코드가 반환된 것을 보니 성공적으로 반영된 것으로 보인다.
상단의 JSON파일 형태의 리스트를 살펴봐도, id 8번으로 입력한 레코드가 제대로 반영된 것을 알 수 있다.
PUT/DELETE (데이터 수정/삭제)
위에서는 데이터 전체를 불러와 그 안에서 조회와 데이터 생성을 했다면, 이번에는 데이터(레코드) 하나만을 불러와 그것에 대해 다뤄보려고 한다. 기본적으로 데이터 수정과 삭제는 각각 하나씩 인스턴스가 해당 요청과 연결되어 동작하는 것이므로, 그 특정 레코드를 불러오는 기능이 필연적이다.
question_list 함수 아래에 question_detail이라는 함수를 새로 만들어 아래 코드와 같이 구현한다.
@api_view(['GET', 'PUT', 'DELETE'])
def question_detail(request, id):
try:
question = Question.objects.get(pk=id)
except Question.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = QuestionSerializer(question)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = QuestionSerializer(question, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
elif request.method == 'DELETE':
question.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
이 함수는 요청(request)과 함께 id값을 인자로 받는다. 만약 인자로 받은 id값에 해당하는 레코드가 없다면 404 에러코드를 반환한다.
이제 각 메서드 별로 어떻게 동작하는지 자세히 살펴보자.
if request.method == 'GET':
serializer = QuestionSerializer(question)
return Response(serializer.data)
먼저 GET 메서드의 경우 question_list의 GET 메서드와 크게 다를 것이 없다. 다른 점은 반환되는 레코드가 단 하나라는 것이다.
# PUT 요청 처리
elif request.method == 'PUT':
serializer = QuestionSerializer(question, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
다음은 PUT 메서드다. serializer에 해당 레코드와 수정할 내용이 담긴 request.data를 함께 받는다. 만약 그 데이터가 유효성 검증에 통과할 경우, 모델에 저장한다. 만약 통과하지 못한다면 400 에러코드를 반환한다.
# DELETE 요청 처리
elif request.method == 'DELETE':
question.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
다음은 DELETE 메서드다. 해당 레코드를 삭제한 뒤 204 상태코드를 반환한다.
새로운 함수를 작성했기 때문에, 그에 따른 URL도 새로 만들어줘야 한다. polls_api의 urls.py에 id값이 담긴 URL을 추가해주자.
from django.urls import path
from . import views
app_name = 'polls_api'
urlpatterns = [
path('question/', views.question_list, name='question_list'),
path('question/<int:id>/', views.question_detail, name='question_detail'),
]
추가해준 뒤 서버를 열어, id가 유효한 레코드 중 아무 페이지를 열어보자. ('/question/{id}')
위와 같은 화면이 노출된다. 아래에는 PUT request를 할 수 있는 폼이 있고, 우측 상단에는 DELETE 요청 버튼이 있다. 이들을 통해 PUT과 DELET 요청을 진행할 수 있다.
'Minding's Programming > Django' 카테고리의 다른 글
[Django] User 항목 모델에 추가 / User 관리 / User생성 / User 권한 (2) | 2024.10.10 |
---|---|
[Django] 클래스 기반의 View, Mixin, Generic View (0) | 2024.10.10 |
[Django] Serilaizer (4) | 2024.10.10 |
[Django] Admin 페이지 편집 (0) | 2024.10.10 |
[Django] 폼(Forms) (0) | 2024.10.08 |