[Django] GET, POST, PUT, DELETE

2024. 10. 10. 15:15·Minding's Programming/Django
728x90
반응형

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 요청을 진행할 수 있다.

 

 

728x90

'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
'Minding's Programming/Django' 카테고리의 다른 글
  • [Django] User 항목 모델에 추가 / User 관리 / User생성 / User 권한
  • [Django] 클래스 기반의 View, Mixin, Generic View
  • [Django] Serilaizer
  • [Django] Admin 페이지 편집
Minding
Minding
  • Minding
    Today's Minding
    Minding
  • 전체
    오늘
    어제
    • 울고넘는 딥러닝 (278)
      • Minding's Baseball (57)
        • MLB Statcast (29)
        • 머신러닝으로 홈런왕 예측하기 (3)
        • 야구칼럼 (12)
        • 야구 규칙, 용어 (1)
        • 2022-23 질롱 코리아 (8)
        • 류현진 등판경기 (4)
      • Minding's Programming (185)
        • 프로그래머스 코딩테스트 (21)
        • Knowledge (44)
        • Numpy & Pandas (6)
        • Excel (3)
        • Git (1)
        • Pygame (11)
        • CV (3)
        • Tensorflow tutorial (4)
        • Kaggle and Dacon (4)
        • 에러 코드 (8)
        • FastAPI (8)
        • Airflow (29)
        • Crawling (6)
        • Django (14)
        • AWS (18)
        • Spark (5)
      • Minding's Reading (30)
        • 머신러닝 딥러닝에 필요한 기초 수학 with 파이.. (2)
        • 칼만필터는 어렵지 않아 (11)
        • 밑바닥부터 시작하는 딥러닝 (6)
        • 메이저리그 야구 통계학 2e (8)
        • 논문읽기 (2)
        • 빅데이터를 지탱하는 기술 (1)
      • Minding's Life (5)
        • 주식 (4)
        • 각종 소식 (1)
  • 블로그 메뉴

    • 홈
    • Baseball
    • Programming
    • Reading
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    게임개발
    머신러닝
    딥러닝
    칼만필터
    넘파이
    칼만필터는어렵지않아
    질롱코리아
    FastAPI
    KBO
    파이썬
    데이터분석
    AWS
    코딩테스트
    pygame
    메이저리그
    에어플로우
    데이터 엔지니어
    칼만필터는어렵지않아파이썬
    Python
    Airflow
    mlb stats api
    프로그래머스
    파이썬게임개발
    django python
    django
    파이게임
    KalmanFilter
    MLB
    칼만필터는어렵지않아python
    야구
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Minding
[Django] GET, POST, PUT, DELETE
상단으로

티스토리툴바