[DRF] VIEW - Mixins
이번에는 View를 짜는데 Mixins 방식으로 한번 View를 작성해 보겠다.
APIView랑 비교해서 얼마나 불필요한 코드 즉 중복되는 코드를 줄일 수 있는지에 대해서 한번 잘 알아보자.
저번에 블로그를 쓸때 너무 유저친화적으로 짠거 같지가 않아서 코드를 새로 다시 만들어서 다시 보여주도록 하려고 한다.
코드를 보자!!!
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.conf import settings
# Create your models here.
class Post(models.Model):
username = models.CharField(blank=False, null=False, unique=True, max_length=10 )
title = models.CharField(max_length=100, blank=False)
content = models.TextField(blank=False)
created_at = models.DateTimeField(auto_now_add=True)
# comment = models.TextField(blank=True, null=True)
class Meta:
ordering = ['username']
serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['username', 'title', 'content', 'created_at']
def validate(self, attrs):
if len(attrs.get('title', ''))>100:
raise serializers.ValidationError({'message': 'title이 100글자를 넘지 않게 해주세요'})
if len(attrs.get('content', ''))>500:
raise serializers.ValidationError({'message' : '내용이 너무 길어요. 500글자 미만으로 작성해주세요'})
return attrs
views.py
from .models import Post
from .serializers import PostSerializer
from rest_framework import generics
from rest_framework import mixins
# Mixins로 view를 구현해 보자.
# Post의 목록을 보여줌
class PostList(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
# Post list를 보여줄 때
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
# 새로운 Post를 만들 때
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
# Post의 detail을 보여줄 때
class PostDetail(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
generics.GenericAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
# Post의 detail을 가지고 온다.
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
# Post를 수정할 때
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
# Post를 삭제
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
그전에 했던 APIView보다 좀 더 간결해진 것을 볼 수 있다. 왜냐하면 CBV(Class Based View)의 특성인 상속을 이용했기 때문이다.
클래스에는 상속이라는 아주 강력한 기능이 있는데 이것을 이용하면 불필요한 코드 중복된 코드를 클래스를 상속받으므로써 줄일 수 있다.
그러면 도대체 어떤것이 상속이 되어있는가? 이것을 django-rest-framework의 공식 github에서 확인이 가능하다.
https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py
django-rest-framework/rest_framework/mixins.py at master · encode/django-rest-framework
Web APIs for Django. 🎸. Contribute to encode/django-rest-framework development by creating an account on GitHub.
github.com
위에 mixins에 클래스에는 어떤 것이 상속되어있는지에 대해 보다가 오늘도 사용하다가 본 함수에 대해서 좀 추가 설명을 해놓기 위해 다시 돌아왔다.
그 함수는 perfom_create(self, serializer)이다. 이 함수의 말 뜻에서도 알 수 있듯이 create가 작동할 때 어떠한 행동을 할 것인가를 나타내는 함수이다.
github 코드를 참고하면 다음과 같이 ListModelMixin과 CreateModelMixin이 정의되어 있는 것을 알 수 있다.
이 외에도 RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin이 이미 정의되어 있다.
아래와 같이 공식 git에서는 우리가 사용했던 ListModelMixin, CreateModelMixin 등등 어떻게 클래스가 만들어져 있고 호출이 되었을 때 어떤 함수가 작동하는지에 대해 정리를 해놨다.
사진을 보면 눈에 익은 코드들이 보인다. 우리가 APIView를 썻을 때 사용한 코드들이 각각 맞는 클래스에 정의가 되어있다. 그렇기에 ListModelMixin, CreateModelMixin을 상속한다면 우리는 코드를 좀더 간결하고 짧게 쓸 수 있다.
그럼 BlogList와 BlogDetail에서 선언해준 queryset과 serializer_class는 어디에서 온 값일까?
이 값 역시 인자로 상속받은 generics.GenericAPIView에서 찾아볼 수 있다.
GenericAPIView는 views.py 상단에서 상속받은 generics에 이미 선언되어 있는 클래스이다.
밑에 공식문서 페이지를 남겨놓겠다.
https://github.com/encode/django-rest-framework/blob/master/rest_framework/generics.py
django-rest-framework/rest_framework/generics.py at master · encode/django-rest-framework
Web APIs for Django. 🎸. Contribute to encode/django-rest-framework development by creating an account on GitHub.
github.com
views.py 상단에서 상속받은 generics의 GenericAPIView를 사용하기 위해서는 공식문서에서 보듯이 우리는 queryset과 serializer_class를 정의 해줘야 한는것이다.
urls.py를 보자
urls.py
from django.urls import path, include
from rest_framework.urlpatterns import format_suffix_patterns
from .views import *
from rest_framework.routers import DefaultRouter
# 밑에는 class view를 기반으로 할 때, 만들어줘야 하는 url방식이다.
urlpatterns = [
path('posts/', PostList.as_view()),
path('posts/<int:pk>/', PostDetail.as_view()),
]
urlpatterns = format_suffix_patterns(urlpatterns)
urls.py는 그전과 동일하게 작성을 했다.
이제 서버를 키고 api를 확인해보자!!
python manage.py runserver
url에 들어가서 확인을 해보니 APIView를 사용했을 때보다 더 깔끔해지고 APIView와 동일하게 결과가 나오는 것을 확인 할 수 있다.
PostDetail이 있는 url로 들어갔을 때 또한 APIView와 동일하게 만들어지는 것을 볼 수 있다.
이로써 DRF의 APIView와 Mixins방식의 view를 보았다. 다음에는 Generic CBV방식의 View를 알아보자!!!
진짜 도움이 많이 된 블로그를 소개하겠다. 이 블로그 주인에게 너무 감사하다!!!!
참고한 블로그
[D.R.F] Mixins로 CRUD 구현하기
안녕하세요 :> 오늘은 지난 시간의 APIView로 CRUD 구현하기에 이어, Mixins을 사용해보도록 하겠습니다. APIView와 Mixins의 가장 큰 차이점은 불필요한 코드의 중복을 얼마나 줄일 수 있는가입니다. APIVi
wisdom-990629.tistory.com
@@