[drf | agiliq] Views and Generic Views

Views and Generic Views

APIVIewgenerics.ListCreateAPIView를 이용해서 뷰를 만들어 볼게요.

Creating Views with APIView

polls lsit와 poll detail API를 순수 장고로 만들어 봤었는데요.여기 클릭
이번에는 APIView로 만들어 볼게요.

새로운 파일을 만들어 볼게요. polls/apiviews.py

from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import get_object_or_404

from .models import Poll, Choice
from  .serializers import PollSerializer

class PollList(APIView):
    def get(self, request):
        polls = Poll.objects.all()[:20]
        data = PollSerializer(polls, many=True).data
        return Response(data)


class PollDetail(APIView):
    def get(self, request, pk):
        poll = get_object_or_404(Poll, pk=pk)
        data = PollSerializer(poll).data
        return Response(data)

urls.py도 바꿀게요.

from django.urls import path

from .apiviews import PollList, PollDetail

urlpatterns = [
    path("polls/", PollList.as_view(), name="polls_list"),
    path("polls/<int:pk>/", PollDetail.as_view(), name="polls_detail")
]

브라우저에서 확인하면 아래 사진과 같아요. http://localhost:8000/polls/

options 요청또한 /polls/ 엔드포인트로 할 수 있어요.

{
    "name": "Poll List",
    "description": "",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ]
}

postman에서 확인 할 경우 아래와 같아요.

Using DRF generic views to simplify code

PollList, PollDetail 작업은 일단은 끝이 났지만 추상화를 통해서 더 효율적으로 접근할 수 있어요.

결국 Django Rest Frameworkdml generic views가 코드 재사용성을 도와주게되요.
serializer 클래스 및 기본 클래스에서 응답 형식과 허용 된 메서드를 유추합니다.

apiviews.py를 아래 코드로 변경하고 urls.py는 그대로 둘게요.

from rest_framework import generics

from .models import Poll, Choice
from .serializers import PollSerializer, ChoiceSerializer,\
    VoteSerializer


class PollList(generics.ListCreateAPIView):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer


class PollDetail(generics.RetrieveDestroyAPIView):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer

위 소스코드를 통해서 기존에 순수 장고로 짯던 코드의 결과적 기능을 그대로 유지할뿐만 아니라 추가적으로 OPTIONS를 이용한 추가적인 데이터도 가지게됩니다.

OPTIONS요청을 /polls/ 엔드포인트에 하게 될 경우 아래의 결과가 나오게되요.

{
    "name": "Poll List",
    "description": "",
    "renders": [
        "application/json",
        "text/html"
    ],
    "parses": [
        "application/json",
        "application/x-www-form-urlencoded",
        "multipart/form-data"
    ],
    "actions": {
        "POST": {
            "id": {
                "type": "integer",
                "required": false,
                "read_only": true,
                "label": "ID"
            },
            // ...
            },
            "question": {
                "type": "string",
                "required": true,
                "read_only": false,
                "label": "Question",
                "max_length": 100
            },
            "pub_date": {
                "type": "datetime",
                "required": false,
                "read_only": true,
                "label": "Pub date"
            },
            "created_by": {
                "type": "field",
                "required": true,
                "read_only": false,
                "label": "Created by"
            }
        }
    }
}

아래 세가지 정보를 얻을 수 있는데요.

  • API가 POST방식을 쓸수 있다는것
  • 필수로 작성해야할 필드 data
  • 데이터 필드의 유형

포스트맨에서는 아래와 같이 볼 수 있어요.

More generic views

apiviews.py를 좀 더 작성해 볼게요.

from rest_framework import generics

from .models import Poll, Choice
from .serializers import PollSerializer, ChoiceSerializer, VoteSerializer


class PollList(generics.ListCreateAPIView):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer


class PollDetail(generics.RetrieveDestroyAPIView):
    queryset = Poll.objects.all()
    serializer_class = PollSerializer


class ChoiceList(generics.ListCreateAPIView):
    queryset = Choice.objects.all()
    serializer_class = ChoiceSerializer


class CreateVote(generics.CreateAPIView):
    serializer_class = VoteSerializer

새로 작성한 apiviews들을 urls.py에 연결 할게요.

from .apiviews import ChoiceList, CreateVote, # ...

urlpatterns = [
    # ...
    path("choices/", ChoiceList.as_view(), name="choice_list"),
    path("vote/", CreateVote.as_view(), name="create_vote"),

]

여기에서 많은 일이 진행되고 있습니다. 재정의하거나 설정해야하는 속성을 살펴 보겠습니다.

  • queryset: 초기 쿼리 셋을 결정합니다. 쿼리 세트는 뷰별로 추가로 필터링, 분할 또는 정렬 할 수 있습니다.
  • serializer_class: 입력 받은 데이터의 유효성 검사와 아웃풋 사용을 위한 직렬화 인풋을 위한 역직렬화에 사용되요.

특히 rest_framework.generic.를통해서 세가지 다른 클래스를 사용해봤는데요. 해당 서브 클래스들은 이름을 통해서 충분히 유추하기 쉬워요.

  • ListCreateAPIView: 엔티티 목록을 가져 오거나 생성합니다. GETPOST를 허용합니다.
  • RetrieveDestroyAPIView: 개별 항목 세부 정보를 검색하거나 항목을 삭제합니다. GETDELETE를 허용합니다.
  • CreateAPIView: 엔티티를 만들 수 있지만 나열 할 수는 없습니다. POST를 허용합니다.

Next Steps

choices/ endpoint를 이용해서 POST 해볼게요.

{
    "choice_text": "Flask",
    "poll": 2
}
{
    "id": 4,
    "votes": [],
    "choice_text": "Flask",
    "poll": 2
}

PollAPI에서 GET메서드 방식을 이용해서 /polls/<pk>/엔드포인트에 접근할 수 있어요. 이 경우 단건이겠조?!

{
    "id": 2,
    "choices": [
        {
            "id": 3,
            "votes": [],
            "choice_text": "Django",
            "poll": 2
        },
        {
            "id": 4,
            "votes": [],
            "choice_text": "Flask",
            "poll": 2
        }
    ],
    "question": "What do you prefer, Flask or Django?",
    "pub_date": "2018-03-12T10:15:55.949721Z",
    "created_by": 1
}

`POST` 메서드를 보내는 중에 실수를하면 API가 경고도 json으로 보내주게되요. `choice_text` 필드가 누락되었다고 말이조.

```python
{
    "poll": 2
}
{
    "choice_text": [
        "This field is required."
    ]
}

상태 코드가 400 Bad Request인지 확인합니다.

Next Steps

현재 작동중인 API가 있지만 더 나은 URL 디자인으로 API를 단순화하고 뷰 세트를 사용하여 일부 코드 중복을 제거 할 수 있습니다. 다음 장에서 그렇게 할 것입니다.

좋은 웹페이지 즐겨찾기