템플릿 장고 URL : /api/like/99
DRF 장고 URL : /api2/post/99/like/
PATCH
가 적합함!urls.py
from django.urls import path
from . import views
## url 패턴이 list나 detail이 아니면 name을 직관적으로 작성
urlpatterns = [
path('post/', views.PostListAPIView.as_view(), name='post-list'),
path('post/<int:pk>/', views.PostRetrieveAPIView.as_view(), name='post-detail'),
path('comment/', views.CommentCreateAPIView.as_view(), name='comment-create'),
path('post/<int:pk>/like/', views.PostLikeAPIView.as_view(), name='post_like'),
]
views.py
from rest_framework.generics import ListAPIView, RetrieveAPIView, CreateAPIView, UpdateAPIView
from blog.models import Post, Comment
from .serializers import CommentSerializer, PostListSerializer, PostRetrieveSerializer
...
class PostLikeAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostListSerializer
Browsable API에서 PATCH 테스트
에러 발생
정상 처리
됨Post 모델 체크
class Post(models.Model):
category = models.ForeignKey('Category', on_delete=models.SET_NULL, blank=True, null=True)
tags = models.ManyToManyField('Tag', blank=True)
title = models.CharField('TITLE', max_length=50)
description = models.CharField('DESCRIPTION', max_length=100, blank=True, help_text='simple one-line text.')
image = models.ImageField('IMAGE', upload_to='blog/%Y/%m/', blank=True, null=True)
content = models.TextField('CONTENT')
create_dt = models.DateTimeField('CREATE DT', auto_now_add=True)
update_dt = models.DateTimeField('UPDATE DT', auto_now=True)
like = models.PositiveSmallIntegerField('LIKE', default=0)
title
과 content
만 필수임!django shell에서 serializer 확인
$ python manage.py shell
>>> from api2.serializers import *
>>>
>>> PostListSerializer()
PostListSerializer():
id = IntegerField(label='ID', read_only=True)
title = CharField(label='TITLE', max_length=50)
image = ImageField(allow_null=True, label='IMAGE', max_length=100, required=False)
like = IntegerField(label='LIKE', required=False)
category = PrimaryKeyRelatedField(allow_null=True, queryset=Category.objects.all(), required=False)
>>>
title
만 필수값임!UpdateAPIView 로직 확인(cdrf) : patch -> partial_update -> partial인자를 True로 변경 -> update
메서드 오버라이딩
필요!partial = kwargs.pop('partial', True)
: (1)부분 수정 True로 설정instance = self.get_object()
: (2)테이블로부터 인스턴스 가져옴serializer = self.get_serializer(instance, data=request.data, partial=partial)
: (3)serializer 준비serializer.is_valid(raise exception=True)
: (4)serializer에서 유효성 체크self.perform_update(serializer)
: (5)DB에 update하여 저장함if getattr(~):
: 'prefetch_related'라는 쿼리문을 사용했을 때 동작하는 코드 -> 현재는 무시!return Response(serializer.data)
: (6)최종적으로 직렬화된 데이터를 client에게 응답 update 메서드 오버라이딩(override)
class PostLikeAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostListSerializer
# update 메서드 오버라이딩
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
# 내부에 like + 1 로직 추가 (이후 serializer의 data변수에 dict 형태로 넣어줌)
data = {'like' : instance.like + 1}
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
결과
문제점
TODO : 기존 응답처럼 like 값 숫자 하나
만 응답으로 내려주도록 변경
views.py
class PostLikeAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostLikeSerializer
# update 메서드 오버라이딩
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
# 내부에 like + 1 로직 추가 (이후 serializer의 data변수에 dict 형태로 넣어줌)
data = {'like' : instance.like + 1}
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
serializers.py
class PostLikeSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['like']
Browsable API로 테스트
key:value
형태로 리턴됨 -> 추가 수정 필요views.py
class PostLikeAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostLikeSerializer
# update 메서드 오버라이딩
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
# 내부에 like + 1 로직 추가 (이후 serializer의 data변수에 dict 형태로 넣어줌)
# data = {'like' : instance.like + 1}
data = instance.like + 1
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
data = instance.like + 1
: dict 자료형이 아니라 int 형으로 data를 만들어서 반환하면?class PostLikeAPIView(UpdateAPIView):
queryset = Post.objects.all()
serializer_class = PostLikeSerializer
# update 메서드 오버라이딩
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
# 내부에 like + 1 로직 추가 (이후 serializer의 data변수에 dict 형태로 넣어줌)
data = {'like' : instance.like + 1}
# data = instance.like + 1
serializer = self.get_serializer(instance, data=data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
# return Response(serializer.data)
return Response(data['like'])
serializer.data
)이 아니라 int 값(data['like']
)을 넣어줌!https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-drf/dashboard