이전에 짜뒀던 API 를 구체적으로 다듬은 다음 모델과 serializer 에서 키에러가 나길래 이것도 조금 수정했다.
특히 views.py 에서 쿼리셋을 .value() 로 받아 serializer 처리를 하는 중 키에러가 나서 serializers.SerializerMethodField()
으로 시리얼라이저를 수정했다.
serializers.py
from rest_framework import serializers
from .models import Book, Review
from taggit.serializers import TagListSerializerField, TaggitSerializer
from taggit.models import Tag
class ReviewSerializer(serializers.ModelSerializer):
author = serializers.SerializerMethodField()
book = serializers.SerializerMethodField()
def get_author(self, obj):
# print(obj["author_id"])
return obj["author_id"]
def get_book(self, obj):
return obj["book_id"]
class Meta:
model = Review
fields = "__all__"
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = "__all__"
class BookTagSerializer(TaggitSerializer, serializers.ModelSerializer):
# 태그 포함 시리얼라이저
tags = TagListSerializerField()
class Meta:
model = Book
fields = "__all__"
class ReviewCreateSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = (
"title",
"content",
"star",
)
class BookSerializer(serializers.ModelSerializer):
author = serializers.SerializerMethodField()
category = serializers.SerializerMethodField()
cover = serializers.SerializerMethodField()
def get_author(self, obj):
# print(obj["author_id"])
return obj["author_id"]
def get_category(self, obj):
return obj["category_id"]
def get_cover(self, obj):
return obj["cover"]
class Meta:
model = Book
fields = "__all__"
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import get_object_or_404
from rest_framework import status, permissions
from .models import Book, Review, Author, TaggableManager
from .serializers import (
BookSerializer,
ReviewSerializer,
BookTagSerializer,
ReviewCreateSerializer,
TagSerializer,
)
from taggit.serializers import TagListSerializerField, TaggitSerializer
from django.views.generic import TemplateView, ListView
from taggit.models import Tag
# Create your views here.
class Main(APIView):
def get(self, request):
# 추천 책
books = Book.objects.all().order_by("likes").values()
# values() 를 했기 때문에 값이 그대로 전달되지 않음 > serializerMethod 를 추가
serializer = BookSerializer(books, many=True)
# 인기 리뷰
reviews = Review.objects.all().order_by("likes").values()
re_serializer = ReviewSerializer(reviews, many=True)
# 태그
tags = Tag.objects.all()
# print(tags)
tag_serializer = TagSerializer(tags, many=True)
serializer_list = [serializer.data, re_serializer.data, tag_serializer.data]
content = {
"status": 1,
"responseCode": status.HTTP_200_OK,
"data": serializer_list,
}
return Response(content)
class CategoryDetail(APIView):
def get(self, request, category_id):
books = Book.objects.filter(category_id=category_id).values()
print(books)
serializer = BookSerializer(books, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
class BookDetail(APIView):
def get(self, request, book_id):
book = get_object_or_404(Book, id=book_id)
serializer = BookTagSerializer(book)
return Response(serializer.data, status=status.HTTP_200_OK)
class ReviewCreate(APIView):
def post(self, request, book_id):
if request.user.is_authenticated:
serializer = ReviewCreateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(author=request.user, book_id=book_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response("로그인 해주십시오", status=status.HTTP_403_FORBIDDEN)
class ReviewUpdate(APIView):
def put(self, request, book_id, review_id):
if request.user.is_authenticated:
my_review = get_object_or_404(Review, id=review_id)
if my_review.author == request.user:
serializer = ReviewCreateSerializer(my_review, data=request.data)
if serializer.is_valid():
serializer.save()
return Response("수정 완료", status=status.HTTP_200_OK)
else:
return Response(
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
else:
return Response("권한이 없습니다.", status=status.HTTP_403_FORBIDDEN)
def delete(self, request, book_id, review_id):
my_review = get_object_or_404(Review, id=review_id)
if my_review.author == request.user:
my_review.delete()
return Response("삭제 완료", status=status.HTTP_200_OK)
else:
return Response("권한이 없습니다.", status=status.HTTP_403_FORBIDDEN)
# html로 태그 전달
class TagCloudTV(TemplateView):
# 모든 태그 추출
template_name = "taggit/tag_cloud_view.html"
class TaggedObjectLV(ListView):
# 특정 태그가 있는 책들
template_name = "taggit/tag_with_book.html"
model = Book
def get_queryset(self):
return Book.objects.filter(tags__name=self.kwargs.get("tags"))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["tags"] = self.kwargs["tags"]
return context
메인페이지는 별도의 로그인 없이도 이용할 수 있으니 별도의 인증 처리를 넣지 않았고, 리뷰 고치기와 삭제는 is_authenticated 를 통해 인증된 사용자인지, 작성자와 request.user 가 같은 사람인지 확인한 다음 실행되도록 만들었다.
책, 리뷰, 태그를 각각 다른 serializer 로 받아서 한 context 리스트에 넣은 다음 return 해줬다. html 에서 response 를 이용해 값을 출력해줄 예정이다.
포스트맨으로 헤더에 인증 토큰을 넣은 뒤 POST, GET, PUT, DELETE 요청을 모두 넣어본 결과 return 값은 제대로 나왔다.