Django

[DRF] VIEW - Mixins

Y0un9Ki 2024. 3. 26. 00:37

이번에는 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이 정의되어 있는 것을 알 수 있다.

이 외에도 RetrieveModelMixinUpdateModelMixinDestroyModelMixin이 이미 정의되어 있다.

 

아래와 같이 공식 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를 사용하기 위해서는 공식문서에서 보듯이 우리는 querysetserializer_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를 알아보자!!!

 

진짜 도움이 많이 된 블로그를 소개하겠다. 이 블로그 주인에게 너무 감사하다!!!!

 

참고한 블로그

https://wisdom-990629.tistory.com/entry/DRF-Mixins%EB%A1%9C-CRUD-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

[D.R.F] Mixins로 CRUD 구현하기

안녕하세요 :> 오늘은 지난 시간의 APIView로 CRUD 구현하기에 이어, Mixins을 사용해보도록 하겠습니다. APIView와 Mixins의 가장 큰 차이점은 불필요한 코드의 중복을 얼마나 줄일 수 있는가입니다. APIVi

wisdom-990629.tistory.com

 

@@