TIL82. WetchaPedia Project : 평균 평점 기준으로 영화 리스트 제공 API 만들기

ID짱재·2021년 11월 14일
0

WeChaCha Project

목록 보기
4/8
post-thumbnail

📌 이 포스팅에서는 평균 평점 기준으로 영화 리스트를 제공하는 API를 만드는 과정에 대해 정리하였습니다.



🌈 평균 평점 기준으로 영화 리스트 제공 API 만들기



🤔 평균 평점 기준의 영화 리스트 제공 API urls.py 설정

✔️ 왓챠피디아는 서비스 핵심이 영화에 대한 선호이기 때문에 모든 영화의 제공을 평균 평점순으로 제공하기로 했다.

✔️ 여기서 "모든" 이란 의미는 영화에 대한 리스트를 제공할 때, 이 영화리스트가 평점 순위의 순서를 가진다는 뜻이다.

✔️ 처음에는 페이지에 출력되는 모든 Data를 한번에 응답해야하는 줄 알았는데, 프론트에서 요청을 보낼 때 여러번의 fetch가 가능한 것을 배웠다.

✔️ 이에 영화 리스트를 제공하는 API를 만들고, 어떤 요청이 들어오든 이를 평점 순으로 제공하기로 했다.

🤔 여러번 fetch를 할 수 있는지 몰랐을 때.. 작성된 코드

✔️ 아래 코드는 프론트쪽에서 한페이지를 구성함에 있어 여러번의 fetch를 요청할 수 있는지 알지 못했을 때 작성한 코드이다.

✔️ 페이지에 보이는데로 필요로한 모든 정보를 담아 한번에 응답하는 방식인데 코드가 무척이나 길어질 수 밖에 없다.

✔️ 뿐만아니라, 다른 영화리스트를 요청하고 싶을 땐 또 다시 이에 대한 코드를 작성해야하기 때문에 확장성이 줄어든다.

class MovieListView(View):
    def get(self, request):
        BOXOFFICE = "박스오피스"
        WATCHA = "왓챠"
        NETFLIX = "넷플릭스"
        boxoffice_movies = (
            Movie.objects.filter(sources__name=BOXOFFICE)
            .annotate(average_point=Avg("rating__rate"))
            .order_by("-average_point")
        )[OFFSET:LIMIT]
        box_category = {}
        box_res = [
            {
                "id": movie.id,
                "title": movie.title,
                "poster_image_url": movie.poster_image_url,
                "released_at": movie.released_at,
                "country": movie.country,
                "ratings": movie.average_point,
                "sources": [source.name for source in movie.sources.all()],
            }
            for movie in boxoffice_movies
        ]
        box_category["category"] = BOXOFFICE
        box_category["feeds"] = box_res
        watcha_movies = (
            Movie.objects.filter(sources__name=WATCHA)
            .annotate(average_point=Avg("rating__rate"))
            .order_by("-average_point")
        )[OFFSET:LIMIT]
        watcha_category = {}
        watcha_res = [
            {
                "id": movie.id,
                "title": movie.title,
                "poster_image_url": movie.poster_image_url,
                "released_at": movie.released_at,
                "country": movie.country,
                "ratings": movie.average_point,
                "sources": [source.name for source in movie.sources.all()],
            }
            for movie in watcha_movies
        ]
        watcha_category["category"] = WATCHA
        watcha_category["feeds"] = watcha_res
        netflix_movies = (
            Movie.objects.filter(sources__name=NETFLIX)
            .annotate(average_point=Avg("rating__rate"))
            .order_by("-average_point")
        )[OFFSET:LIMIT]
        netflix_category = {}
        netflix_res = [
            {
                "id": movie.id,
                "title": movie.title,
                "poster_image_url": movie.poster_image_url,
                "released_at": movie.released_at,
                "country": movie.country,
                "ratings": movie.average_point,
                "sources": [source.name for source in movie.sources.all()],
            }
            for movie in netflix_movies
        ]
        netflix_category["category"] = NETFLIX
        netflix_category["feeds"] = netflix_res
        result.append(box_category)
        result.append(watcha_category)
        result.append(netflix_category)
        return JsonResponse({"message": result}, status=200)

🤔 확장성을 가진 API로 사용되기 위해 수정된 코드

✔️ 이에 여러 요청에 구애받지 않고, 필요한 영화리스트르 목록을 평점순으로 제공할 수 있는 API를 만들어보기로 하였다.

✔️ 코드가 훨씬 간결해지고, 검색에도 같은 View를 사용할 수 있기 때문에 이전보다 확장성을 갖출 수 있게 되었다.

✔️ 특히, 여러가지 조건을 가지고 filter를하기 위해 Q객체를 이용했는데, 이를 OR 또는 AND와 함께 사용하면서 조건을 제어할 수 있었다.

✔️ 이 과정에서 프론트에서 무비리스트의 수량을 조절할 수 있는 OFFSET과 LIMIT을 함께 사용하였는데, 별다른 요청이 없으면 기본값이 15개를 제공하는 방식이다.

from django.http import JsonResponse
from django.views import View
from django.db.models import Q, Avg
from .models import *
class MovieListView(View):
    def get(self, request):
        source = request.GET.get("source")
        rating = request.GET.get("rating")
        keyword = request.GET.get("keyword")
        OFFSET = int(request.GET.get("offset", 0))
        LIMIT = int(request.GET.get("display", 15))
        category = {
            "박스오피스": "박스오피스 영화 순위",
            "왓챠": "왓챠 영화 순위",
            "넷플릭스": "넷플릭스 영화 순위",
            "평균별점": "평균별점이 높은 작품",
        }
        result = {}
        q = Q()
        if source:
            q.add(Q(sources__name=source), q.AND)
            result["category"] = category[source]
        if keyword:
            q.add(Q(staffs__name__icontains=keyword) | Q(title__icontains=keyword), q.AND)
        if rating:
            q = Q()
            result["category"] = category[rating]
        movies = (
            Movie.objects.filter(q)
            .annotate(average_point=Avg("rating__rate"))
            .order_by("-average_point")[OFFSET : OFFSET + LIMIT]
        )
        result["movies"] = [
            {
                "id": movie.id,
                "title": movie.title,
                "poster_image_url": movie.poster_image_url,
                "released_at": movie.released_at,
                "country": movie.country,
                "ratings": round(movie.average_point, 1) if movie.average_point != None else 0,
                "sources": [source.name for source in movie.sources.all()],
            }
            for movie in movies
        ]
        return JsonResponse({"message": result}, status=200)

✔️ 이를 바탕으로 API명세서를 만든 결과는 아래와 같다.

profile
Keep Going, Keep Coding!

0개의 댓글