본문 바로가기

인턴 프로젝트

미니 요기요 프로젝트 (7) - 메뉴 타임라인

  • 기획의도
    • 구독 중인 레스토랑의 신메뉴 출시, 변경 정보(이미지, 가격, 상세정보)를 한눈에 볼 수 있게 함
  • 화면

  • 코드
from django.db.models import Count, Prefetch, Q
from django.http import JsonResponse
from django.views.generic.base import View

from accounts.mixins import LoginRequiredMixin
from menu.models import MenuTimeLine
from yosigy.models import YosigyMenu
from timeline.models import MenuTimelineComment


class MenuTimeLineAPIView(LoginRequiredMixin, View):

    def get(self, request, *args, **kwargs):
        user = request.user

        menu_timeline_queryset = (
            MenuTimeLine.objects
            .select_related(
                'menu',
                'menu__restaurant',
            ).prefetch_related(
                'like',
                'menu__tastes',
                Prefetch('menutimelinecomment_set',
                         queryset=(
                             MenuTimelineComment.objects
                             .select_related('menu_timeline')
                             .filter(is_active=True)
                                )
                         )
            ).filter(
                Q(menu__restaurant__subscribers=user) &
                (~Q(menutimelinecomment__id=None) |
                 Q(menutimelinecomment=None))
            ).annotate(
                comment=Count('menutimelinecomment'),
            )
            .order_by('-created_time')
        )

        yosigymenus = (
            YosigyMenu.objects.all()
        )

        if menu_timeline_queryset:
            last_created_cart = user.cart_set.order_by(
                '-created_time').values_list('id', flat=True)[0]

            liked_menu_timeline= [timeline['id'] for timeline in list(user.menutimeline_set.values('id'))]

            menutimeline_json_data = [
                {
                    'timeline_id': menutimeline_obj.id,
                    'menu_id': menutimeline_obj.menu.id,
                    'menu_name': menutimeline_obj.menu.name,
                    'restaurant_title': menutimeline_obj.menu.restaurant.title,
                    'delivery_charge': menutimeline_obj.menu.restaurant.delivery_charge,
                    'min_order_price': menutimeline_obj.menu.restaurant.min_order_price,
                    'restaurant_img': menutimeline_obj.menu.restaurant.img.url,
                    'status': menutimeline_obj.status,
                    'prior_menu_price': menutimeline_obj.prior_menu_price,
                    'prior_menu_detail': menutimeline_obj.prior_menu_detail,
                    'prior_menu_img': menutimeline_obj.prior_menu_img.url if menutimeline_obj.prior_menu_img else '',
                    'prior_menu_is_yosigy': menutimeline_obj.prior_menu_is_yosigy,
                    'prior_menu_is_set_menu': menutimeline_obj.prior_menu_is_set_menu,
                    'post_menu_price': menutimeline_obj.post_menu_price,
                    'post_menu_detail': menutimeline_obj.post_menu_detail,
                    'post_menu_img': menutimeline_obj.post_menu_img.url if menutimeline_obj.post_menu_img else '',
                    'post_menu_is_yosigy': menutimeline_obj.post_menu_is_yosigy,
                    'post_menu_is_set_menu': menutimeline_obj.post_menu_is_set_menu,
                    'is_recommended': menutimeline_obj.is_recommended,
                    'created_time': menutimeline_obj.created_time.strftime('%Y.%m.%d %H:%M:%S'),
                    'like': (True if menutimeline_obj.id in liked_menu_timeline else False),
                    'like_count': menutimeline_obj.like.count(),
                    'comment_count': menutimeline_obj.menutimelinecomment_set.count(),
                }
                for menutimeline_obj in menu_timeline_queryset
            ]

            for index, menutimeline_obj in enumerate(menu_timeline_queryset):
                temp_taste_list = []
                for taste in menutimeline_obj.menu.tastes.all():
                    temp_taste_list.append(taste.name)
                menutimeline_json_data[index]['tastes'] = temp_taste_list

                for yosigymenu in yosigymenus:
                    if yosigymenu.menu.pk == menutimeline_obj.menu.pk:
                        menutimeline_json_data[index]['yosigy_id'] = yosigymenu.yosigy.pk
                        break

            json_data = {
                'menutimeline': menutimeline_json_data,
                'cart_id': last_created_cart,
            }
        else:
            json_data = {
                'message': '구독 중인 레스토랑이 없거나 전해드릴 메뉴 알림이 없습니다.'
            }
        return JsonResponse(
            data=json_data
        )
  • 테스트 코드
from django.test import TestCase
from django.urls import reverse

from accounts.models import User
from menu.models import Menu
from restaurant.models import Restaurant


class MenuTimeLineTest(TestCase):
    def setUp(self):
        self.user_subscribing_restaurant = User.objects.create_user(username='홍길동', email='', password='1',
                                             address='서울시 서초구 서초2동 사랑의 교회')
        self.user_without_subscribing = User.objects.create_user(username='홍두깨', email='', password='1',
                                                                 address='서울시 서초구 서초2동 사랑의 교회')
        self.restaurant_create_one_menu = Restaurant.objects.create(
            name='굽내치킨1', title='굽내치킨1-서초점',
            min_order_price=10000, delivery_charge=1000, estimated_delivery_time='20:00',
            operation_start_hour='11:00', operation_end_hour='20:00', )
        self.restaurant_update_menu = Restaurant.objects.create(
            name='굽내치킨2', title='굽내치킨2-서초점',
            min_order_price=10000, delivery_charge=1000, estimated_delivery_time='20:00',
            operation_start_hour='11:00', operation_end_hour='20:00', )
        self.restaurant_without_menu_alarm = Restaurant.objects.create(
            name='굽내치킨3', title='굽내치킨-서초점',
            min_order_price=10000, delivery_charge=1000, estimated_delivery_time='20:00',
            operation_start_hour='11:00', operation_end_hour='20:00', )
        self.user_subscribing_restaurant.subscribed_restaurants.set = self.restaurant_create_one_menu
        self.created_menu = Menu(
            restaurant=self.restaurant_create_one_menu,
            name='갈비천왕',
            detail='갈비 맛입니다.',
            price=20000,
            type='양념류',
            img='test.jpg',
        )
        self.created_menu.save()

    def test_when_menutimeline_empty_return_message(self):
        '''
        타임라인이 없는 경우 메시지
        '''
        # Given
        self.client.login(username='홍길동', password='1')
        # When
        response = self.client.get(reverse('timeline_api:menutimeline'))
        message = response.json()['message']
        # Then
        self.assertEqual(message, '구독 중인 레스토랑이 없거나 전해드릴 메뉴 알림이 없습니다.')
  • 어려웠던 점
    • 변경 사항을 저장하는 타임라인 테이블에 어떤 필드가 변경되었는지 판단하는 것
  • 해결방법
    • 변경 정보를 저장해야 하는 필드를 이전, 이후로 나눠서 각각 저장했다. 
  • 느낀점
    • 이렇게 대충 생각하고 하니까 변경사항이 1개만 있는 경우 null 값이 많아졌다.