상세 컨텐츠

본문 제목

DRF 개념

django

by 개복신 개발자 2022. 8. 8. 19:22

본문

728x90
반응형

REST API란?

http method + 원하는 정보 or 추가,수정 원하는 정보

의 형식으로 만든 api

 

http method

1. get

목록 가져오기, 상세정보 가져오기 등

2. post

새 포스팅 작성, 새 댓글 작성

ex) post/1/comments

3.put

포스팅 정보 갱신, 업데이트

4.delete

포스팅 삭제

 

django-rest-framework 기능

1.serializer, ModelSerializer를 통한 데이터 유혀성 검증 및 데이터 직렬화

2.parser를 통한 데이터 처리

3. 요청 처리

    a. APIview

    b. Generic

    c. ViewSet

    d. ModelViewSets

위 4가지 방식으로 요청 처리

4.각종 renderer를 통해 다양한 응답 포맷 지원

5.인증/권환 -JWT 지원

6. Throttling -> 최대 호출 횟수 지원

 

 


1. 장고 restframework 설치 

pip install djangorestframework ~= version

프로젝트 url에 

path('api-auth/', include('rest-framework.urls') 추가

installed_apps에 rest_framework 추가

 

2.앱 생성

기타 작업들 알아서 처리

 

3. 모델 작성

class Post(models.Model):
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

4. serializers.py 작성

from rest_framework.serializers import ModelSerializer
from .models import Post


class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = '__all__'

ModelSerializer를 상속하여 PostSerializer 클래스 작성

Post 모델을 가져와 모든 필드들 등록했음

ModelForm과 매우 비슷한 형식

 

-serializer와 modelserializer

Serializer는 JSON문자열을 생성하고

ModelSerializer 내부 모델(db)를 serializer(직렬화) 형식으로 처리하는 역할

 

 

5. views.py 작성

ModelViewSet을 상속 받아서 queryset을 가져온다. PostSerializer 형식으로 알아서 처리해준다

from rest_framework.viewsets import ModelViewSet
from .serializers import PostSerializer
from .models import Post

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

    # def dispatch(self, request, *args, **kwargs):
    #     print("request.body :", request.body)  # print 비추천, logger 추천
    #     print("request.POST :", request.POST)
    #     return super().dispatch(request, *args, **kwargs)



# def post_list(request):
#     # 2개 분기
#     pass
#
#
# def post_detail(request, pk):
#     # request.method # => 3개 분기
#     pass

6. urls.py 작성

from django.urls import include, path
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register('post', views.PostViewSet)  # 2개 URL을 만들어줍니다.
# router.urls  # url pattern list

urlpatterns = [
    path('', include(router.urls)),
]

router.urls에 2개의 url이 등록되어있음

post_list, post_detail등의 url


JSON

직렬화 - json(dumps(list안의 dict)) -객체를 전송 가능한 형태로 만듦

비직렬화 - json.loads(비직렬화 할 data) - 직렬화된 파일을 다시 객체의 형태로 만드는 것

 

-장고 타입 models or queryset에 대해서는 직렬화 rule이 없다

따라서 jsonencoder를 정의하여 instance나 queryset에 대한 직렬화 규칙을 정의한다

 

아래코드

from django.core.serializers.json import DjangoJSONEncoder
from django.db.models.query import QuerySet
# 커스텀 JSON Encoder를 정의
	class MyJSONEncoder(DjangoJSONEncoder):
		def default(self, obj):
			if isinstance(obj, QuerySet):
				return tuple(obj)
			elif isinstance(obj, Post):
				return {'id': obj.id, 'title': obj.title, 'content': obj.content}
			elif hasattr(obj, 'as_dict'):
				return obj.as_dict()
		return super().default(obj)
data = Post.objects.all()

serializer custom

author 필드 추가했을 때 

class AuthorSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ['username', 'email']


class PostSerializer(serializers.ModelSerializer):
    # author_email = serializers.ReadOnlyField(source='author.email')
    author = AuthorSerializer()

1. author_email을 ReadOnlyField로 추가

2. 따로 중복 serializer를 작성하여 넣기


구현해야 될 기능 총 5가지

list - get(목록), post(새 글 생성)

detail - get(상세 페이지 조회), put(상세 페이지 수정), delete(글 삭제)

 

list에서 post_list를 조회하는 기능만 추가하기-generic 이용하기

from rest_framework import generics

class PublicPostListAPIView(generics.ListCreateAPIView):
    queryset = Post.objects.all()  # filter(is_public=True)
    serializer_class = PostSerializer
    
 class PostViewSet(ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

viewset은 5가지 기능을 모두 제공함


ApiView를 통한 DRF 구현

  • 하나의 CBV 이므로 하나의 URL 만 처리 가능합니다.
  • 각 요청 method (get, post, put, delete) 에 맞게 멤버함수를 구현하면, 해당 method 요청이 들어올 때 호출됩니다.
  • 호출이 되면 호출 이전 단계(initial) 에서 다음을 처리합니다.
    (1) 직렬화 / 비직렬화 처리
    (2) 인증 체크
    (3) 사용량 제한 체크 : 호출 허용량 범위인지 체크
    (4) 권한 클래스 지정 : 비인증 / 인증 유저에 대해 해당 API 호출을 허용할 것인지 결정
    (5) 요청한 버전 체크 : 요청된 API 버전 문자열을 탐지하여, request.version 에 저장

구현 예시

views.py

from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Post
from .serializers import PostSerializer

""" list / create """
class PostListAPIView(APIView):
	def get(self, request):	
		serializer = PostSerializer(Post.objects.all(), many=True)
  		return Response(serializer.data)
	def post(self, request):
 		serializer = PostSerializer(data=request.data)
  		if serializer.is_valid():
   			serializer.save()
   			return Response(serializer.data, status=201)
   		return Response(serializer.erros, status=400)

from django.shortcuts import get_object_or_404

""" detail / update / delete """
class PostDetailAPIView(APIView):
	def get_object(self, pk):
		return get_object_or_404(Post, pk=pk)
 
 	def get(self, request, pk, format=None):
 		post = self.get_object(pk)
   		serializer = PostSerializer(post)
   		return Response(serializer.data)
        
   	def put(self, request, pk):
		post = self.get_object()
   		serializer = PostSerializer(post, data=request.data)
   		if serializer.is_valid():
			serializer.save()
 			return Response(serializer.data)
 		return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
 	def delete(self, request, pk):
		post = self.get_object(pk)
		post.delete()
		return Response(status=status.HTTP_204_NO_CONTENT)

urls.py

from django.urls import path, include
from . import views

urlpatterns = [
	path('post', views.PostListAPIView.as_view()),
 	path('post/<int:pk>/', views.PostDetailAPIView.as_view()),
]

mixins를 통한 DRF 구현

APIView에서는 request method 마다 직접 serializer 처리를 반복하였다.

이러한 번거로움은 mixins를 사용하면 간소화 가능하다

 

from rest_framework.response import Response
from rest_framework import generics
from rest_framework import mixins
from .models import Post
from .serializers import PostSerializer

class PostListMixins(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
	queryset = Post.objects.all()
	serializer_class = PostSerializer
    
	def get(self, request, *args, **kwargs):
		return self.list(request)
        
	def post(self, request, *args, **kwargs):
		return self.create(request)
    
class PostDetailMixins(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
	queryset = Post.objects.all()
	serializer_class = PostSerializer
    
	def get(self, request, *args, **kwargs):
		return self.retrieve(request)
        
	def put(self, request, *args, **kwargs):
		return self.update(request)
        
	def delete(self, request, *args, **kwargs):
		return self.delete(request)        

generic APIVIew를 통한 DRF 구현

DRF에서 지원하는 generic APIView

  • generics.CreateAPIView : 생성
  • generics.ListAPIView : 목록
  • generics.RetrieveAPIView : 조회
  • generics.DestroyAPIView : 삭제
  • generics.UpdateAPIView : 수정
  • generics.RetrieveUpdateAPIView : 조회 / 수정
  • generics.RetrieveDestroyAPIView : 조회 / 삭제
  • generics.ListCreateAPIView : 목록 / 생성
  • generics.RetrieveUpdateDestroyAPIView : 조회 / 수정 / 삭제
from rest_framework import generics
from .models import Post
from .serializers import PostSerializer

class PostListGenericAPIView(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

class PostDetailGenericAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer

Viewset을 통한 DRF 구현

2개의 URL별로 구현된 5개의 메서드를 하나의 단일클래스에 제공합니다.

 

from .models import Post
from .serializers import PostSerializer
from rest_framework import viewsets

class PostViewSet(viewsets.ModelViewSet):
	queryset = Post.objects.all()
	serializer_class = PostSerializer
    
post_list = PostViewSet.as_view({'get': 'list',})
post_detail = PostViewSet.as_view({'get': 'retrireve'})

renderer 

보여주는 방식 지정

-jsonrenderer(디폴트)

 

-browserapirenderer

-templatehtmlrenderer

지정된 템플릿을 통한 렌더링

from rest_framework import generics
from rest_framework.decorators import api_view, action
from rest_framework.generics import RetrieveAPIView
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet


class PostDetailAPIView(RetrieveAPIView):
    queryset = Post.objects.all()
    renderer_classes = [TemplateHTMLRenderer]
    template_name = 'instagram/post_detail.html'

    def get(self, request, *args, **kwargs):
        post = self.get_object()
        return Response({
            'post': post,
        })

renderer_class 지정, template_name 지정하면 해당 template 상으로 정보를 보여줄 수 있도록 설정 가능

 

장식자 방식 가능

@api_view(['GET'])
@renderer_classes([JSONRenderer])

 

--커스텀 유효성 검사

serializer 내부에서 함수 지정

이때 함수에는 반드시 validate_~~의 형식이어야 함

# serializer 클래스 내부에 함수
def validate_title(self, value):
	if 'django' not in value:
    	raise ValidationError("제목에 필히 django가 필요합니다")
    return value

perform_create 커스텀 가능

perform_create --> serializer 저장 기능 -- form.save와 비슷한 기능

class PostViewSet(ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    # authentication_classes = []  # 인증이 됨을 보장받을 수 있습니다.
    permission_classes = [IsAuthenticated, IsAuthorOrReadonly]
    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = ['message']

    def perform_create(self, serializer):
        author = self.request.user  # User or AnonymousUser
        ip = self.request.META['REMOTE_ADDR']
        serializer.save(author=author, ip=ip)

    @action(detail=False, methods=['GET'])
    def public(self, request):
        qs = self.get_queryset().filter(is_public=True)
        serializer = self.get_serializer(qs, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['PATCH'])
    def set_public(self, request, pk):
        instance = self.get_object()
        instance.is_public = True
        instance.save(update_fields=['is_public'])
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

-perform_create 메소드(perform_update, perform_destroy)

author와 ip는 user가 지정하면 안되는 영역이기에 perform_create 메소드에서

지정하여 저장할 때 컴퓨터가 알아서 처리하도록 설정한다.

 

-models.py

model에서 ip는 사용자가 임의로 변경해서는 안되는 부분이기 때문에

editable = False 속성을 넣으면 serializer 필드에 ip 추가해도 사용자가 변경할 수 없다


authentication

반응형

'django' 카테고리의 다른 글

장고 admin을 통한 데이터 관리  (0) 2022.04.05
장고 모델 필드  (0) 2022.03.31
장고 orm  (0) 2022.03.31
웹 프레임워크  (0) 2022.03.28
detail 페이지 오답노트  (0) 2022.03.21

관련글 더보기

댓글 영역