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 구현
구현 예시
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 구현
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
장고 admin을 통한 데이터 관리 (0) | 2022.04.05 |
---|---|
장고 모델 필드 (0) | 2022.03.31 |
장고 orm (0) | 2022.03.31 |
웹 프레임워크 (0) | 2022.03.28 |
detail 페이지 오답노트 (0) | 2022.03.21 |
댓글 영역