WEB/Django

[Django ViewSet] ViewSet 으로 Filter & Permission & Validation

김쿸후 2021. 5. 16. 00:00

1. ViewSet 

https://www.django-rest-framework.org/api-guide/viewsets/

 

Viewsets - Django REST framework

viewsets.py After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. — Ruby on Rails Documentation Django REST framework allows you to combine

www.django-rest-framework.org

1.1 ViewSet이란

View 들의 집합

Django REST Framework 에서 여러가지 API를 통합하여 하나의 Set으로 제공한다. 

 

1.2 ViewSet으로 refactoring하기

  • 과거의 CBV 방법
    • 참고 : https://gimkuku0708.tistory.com/37
    • 함수 정의를 통해 get, post 함수를 직접 정의해주어야 한다. 
    • List와 Detail class를 나눠주어야 한다. 
 

[Django View] Postman 사용하여 api 주고 받기

1. Postman 1.1 Postman 이란 더보기 A powerful GUI platform to make your API development faster & easier, from building API requests through testing, documentation and sharing. 즉, API request를 만들..

gimkuku0708.tistory.com

class PostList(APIView):
     # 작성한 포스트를 모든 데이터를 가져오는 API 만들기
     def get(self, request):
         post = Post.objects.all()  # get queryset of the Post
         serializer = PostSerializer(post, many=True)  # Serialize it to python native data type
         return Response(serializer.data)

     #새로운 포스트를 create하는 api
     def post(self, request):
         data = request.data
         serializer = PostSerializer(data=data)
         if serializer.is_valid():
             serializer.save()  # save to DB
             return Response(serializer.data)
         return Response(serializer.errors)

 

 

  • ViewSet 방법 
    • mixins 와 viewsets를 상속받아서 적용
    • 함수를 따로 만들지 않아도 get post 등의 함수가 구현되어 있음
class PostViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = PostSerializer
    queryset = Post.objects.all()
여기서 잠깐?

1. Mixins 란 : 특정한 클래스에 상속을 통해 기능을 추가하는 것. 
rest_framework.mixins 에는 기능들이 미리 구현이 되어 있음
CreateModelMixin :  .create(request, *args, **kwargs) method
ListModelMixin :  .list(request, *args, **kwargs) method
RetrieveModelMixin : .retrieve(request, *args, **kwargs) method
UpdateModel : .update(request, *args, **kwargs) method
MixinDestroyModelMixin : .destroy(request, *args, **kwargs) method

2. ViewSet의 종류
GenericViewSet : 기본적인 종류만 제공(get_object, get_queryset 등)
-> 사용을 할 때, mixin을 오버라이딩 하거나 명시적으로 함수를 정의해주어야 함. 
ModelViewSet : action이 제공됨 ( .list(), .retrieve(), .create(), .update())
ReadOnlyModelViewSet : read-only인 action이 제공됨 (.list() , .retrieve()) 

 

즉, 단순히 ViewSet과 Mixin을 상속받는 것으로 post get 등의 함수가 구현된다. 

내가 사용한 mixins는 ListModelMixin인데, 이는 쿼리셋을 list 형태로 반환해주는 함수이다.

 

 

2. Filter

https://django-filter.readthedocs.io/en/latest/ref/filters.html#filter-method

 

Filter Reference — django-filter 2.4.0 documentation

BooleanFilter This filter matches a boolean, either True or False, used with BooleanField and NullBooleanField by default. IsoDateTimeFilter Uses IsoDateTimeField to support filtering on ISO 8601 formatted dates, as are often used in APIs, and are employed

django-filter.readthedocs.io

2.1 FilterSet란 

filtering 작업( queryset에서 특정 queryset을 고르는 작업 ) 을 손쉽게 사용하도록 DRF(Django REST Framework)에서 제공하는 속성.

클라이언트가 접근하는 API url에 붙은 query parameter을 자동으로 필터의 옵션으로 인식하고 필터링을 함. 

 

2.2 FilterSet 사용 방법

  • class Meta : 
    • filterable한 모델 정의
    • 사용할 필드 정의
    • Disable fields : exclude
    • Ordering : order_by
    • Group fields : together

FilterSet class Meta 예시 : 

import django_filters

class PostFilter(django_filters.FilterSet):
    class Meta:
        model = Post
        fields = ['author', 'content', 'upload_date']
        order_by = ['upload_date']

 

  • filter method 사용하기
    • filtering 되는 data의 형식에 따라 다양한 filter가 존재한다. ( Charfilter, Booleanfilter 등 )
    • 자주 사용하는 argument
      1. name : model 필드 이름을 필터링 
      2. lookup_expr : 필터링 할 때 필드를 가져옴__구문을 이용하여 model 필드를 필터링할 수 있다. (ex : year__gt)

Filter method 예시 : 

class F(FilterSet):
    id__in = NumberInFilter(field_name='id', lookup_expr='in')

    class Meta:
        model = User

 

  • customized filter method 사용하기
    • 사용자는 method를 이용하여 filter 방법을 customizing 할 수 있다. 
      1. output에 따라 filter 선택
      2. 변수 = 선택한 filter(method = "사용자method이름")
      3. def 사용자method이름(params): 로 정의

Custom Filter method 예시 : 

class PostFilter(FilterSet):
    author_value = filters.CharFilter(method='filter_author')
    is_good_value = filters.BooleanFilter(method='filter_is_good')

    class Meta:
        model = Post
        fields = '__all__'

    def filter_author(self, queryset, value, *args):
        return queryset.filter(author=args[0])

    def filter_is_good(self, queryset, value):
        if value == True:
            return queryset.filter(is_good=True)
        else:
            return queryset.filter(is_good=False)

 

 

3. Permission

https://www.django-rest-framework.org/api-guide/permissions/

 

Permissions - Django REST framework

 

www.django-rest-framework.org

3.1 Permission이란

사용자가 해당 작업을 할 권한이 있는지를 검사하는 것.
모델의 제일 처음에 작동됨. 

즉 어떠한 사용자가 API에 접근해 특정 작업을 수행하려 할 때, request에 담겨오는 user의 정보에 따라 작업의 권한을 줄지 말지 결정하는 것.

 

3.2 DRF에서 Permission 사용하기 

  • AllowAny (Default) : 무조건 view 호출 허용
  • IsAuthenticated : 인증된 user의 호출만 허용
  • IsAuthenticatedOrReadOnly : 인증된 user의 호출 허용, 비인증 user는 읽기 권한만 허용

ViewSet 내부의 permission_classes 에 추가해주면 됨.

 

Permission 예시 :

from rest_framework.permissions import IsAuthenticatedOrReadOnly

class PostViewSet(ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

    permission_classes = [
        IsAuthenticatedOrReadOnly,
    ]

 

4. Validation

https://docs.djangoproject.com/en/3.2/ref/validators/

 

Validators | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

4.1 Validation이란

들어온 data가 형식에 맞는지에 대한 유효성 검사를 하는 것.

Validation의 경우 ModeSerializer를 사용하면 자동으로 처리가 가능하다.

 

4.2 기본 Validation

우선 장고에서 기본으로 제공해주는 validator를 모델에 추가한다. 장고는 다음과 같은 validator를 기본으로 제공한다.

class EmailValidator(message=None, code=None, allowlist=None)
class URLValidator(schemes=None, regex=None, message=None, code=None)
class MaxLengthValidator(limit_value, message=None)
class MinLengthValidator(limit_value, message=None)
...

model.py

from django.db import models
from django.core.validators import MinLengthValidator

title_validator = MinLengthValidator(3, "길이가 너무 짧습니다.")

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=10, validators=[title_validator])
    content = models.TextField()

 

4.3 Custom Validation

validate 메소드를 만든 후,

valdation을 적용하고 싶은 모델 필드에 리스트의 요소로 추가 시켜주면 된다.

 

model.py

from django.core.exceptions import validationError

def validate_email(value):
   if not "@" in value:
       raise ValidationError("Not a valid email")
   else:
       return value