본문 바로가기

인턴 프로젝트

미니 요기요 프로젝트(5) - 레스토랑 구독하기, 구독 중인 레스토랑

1. 레스토랑 구독하기

  • 기획 의도
    • 타임라인에 구독한 레스토랑에 대한 정보, 레스토랑의 메뉴 정보를 보여주기 위해 구독 기능 만듦
  • 화면

구독하기 OR 구독취소 Toggle

  • 코드
class RestaurantSubscribeCreateAPIView(LoginRequiredMixin, View):
    def post(self, request, *args, **kwargs):
        user = request.user
        restaurant_id = self.kwargs['restaurant_id']
        try:
            restaurant = Restaurant.objects.get(pk=restaurant_id)
            if user.subscribed_restaurants.filter(pk=restaurant_id):
                user.subscribed_restaurants.remove(restaurant)
                json_data = {
                    "message": "구독 취소",
                    "subscribe_flag": True,
                }
                return JsonResponse(
                    json_data,
                )
            else:
                user.subscribed_restaurants.add(restaurant)
                user.save()
                json_data = {
                    "message": "구독 성공",
                    "subscribe_flag": False,
                }
                return JsonResponse(
                    json_data,
                )
        except:
            json_data = {
                "message": "구독할 레스토랑이 없습니다.",
            }
            return JsonResponse(
                json_data,
                status=HTTPStatus.BAD_REQUEST,
            )
  • 테스트 코드
class SubscribeTestCase(TestCase):
    def setUp(self):
        self.username = 'mypage_user'
        self.password = 'mypage_password!'
        self.user = User.objects.create_user(
            username=self.username, password=self.password)
        self.restaurant = Restaurant.objects.create(
            name='굽내치킨', title='굽내치킨-서초점', estimated_delivery_time='00:20',
            min_order_price=10000, delivery_charge=1000, operation_end_hour='10:00',
            operation_start_hour='10:00', )

    def test_return_OK_when_subscribe_success(self):
        '''
        로그인 유저가 레스토랑 구독 시 성공 반환
        '''
        # Given
        self.client.login(username=self.username, password=self.password)
        self.user.subscribed_restaurants.set = self.restaurant
        self.user.save()
        url = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        # When
        response = self.client.post(url)
        # Then
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertIn(self.restaurant, Restaurant.objects.filter(subscribers=self.user))

    def test_return_OK_when_subscribe_cancel_success(self):
        '''
        로그인 유저가 구독 중인 레스토랑 구독 취소 시 성공 반환
        '''
        # Given
        self.client.login(username=self.username, password=self.password)
        url_save = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        url_cancel = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        # When
        self.client.post(url_save)
        response = self.client.post(url_cancel)
        # Then
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertNotIn(self.restaurant, Restaurant.objects.filter(subscribers=self.user))

    def test_return_BAD_REQUEST_when_try_subscribe_without_restaurant_id(self):
        '''
        레스토랑 id가 없는 상태에서 구독 시도 시 BAD REQUEST 리턴
        '''
        # Given
        self.client.login(username=self.username, password=self.password)
        self.unvalid_restaurant_id = 999999999999
        url = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.unvalid_restaurant_id,
        })
        # When
        response = self.client.post(url)
        # Then
        self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST)

    def test_return_OK_when_subscribed_restaurants_on_request(self):
        '''
        구독중인 레스토랑 요청 시 OK 반환
        '''
        # Given
        self.client.login(username=self.username, password=self.password)
        self.user_id = self.user.id
        url_save = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        url_lookup = reverse("restaurant_api:subscribed_restaurant_api", kwargs={
            'user_id': self.user_id,
        })
        # When
        self.client.post(url_save)
        response = self.client.get(url_lookup)
        # Then
        self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_return_OK_when_subscribe_cancel_and_no_subscribed_restaurants_on_request(self):
        '''
        레스토랑 구독 취소 후 레스토랑 없는 데 요청한 경우 OK 반환
        '''
        # Given
        self.client.login(username=self.username, password=self.password)
        self.user_id = self.user.id
        url_save = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        url_cancel = reverse("restaurant_api:restaurant_subscribe_api", kwargs={
            'restaurant_id': self.restaurant.id,
        })
        url_lookup = reverse("restaurant_api:subscribed_restaurant_api", kwargs={
            'user_id': self.user_id,
        })
        # When
        self.client.post(url_save)
        self.client.post(url_cancel)
        response = self.client.get(url_lookup)
        # Then
        self.assertEqual(response.status_code, HTTPStatus.OK)
        self.assertNotIn(self.restaurant, Restaurant.objects.filter(subscribers=self.user))
  • 어려웠던 점

딱히 없다.

  • 해결방법
  • 느낀점

구독하기 버튼을 누르면 구독취소 문구가 나오고 구독취소 버튼을 누르면 구독하기 문구가 나오는 기능이다. API가 동일하다. 버튼 클릭시 같은 API를 호출하고 ORM에서 구독중인지 아닌지를 따져서 문구를 바꿔주는 형태였다. 멘토님께서 이걸 보시고 API 기능마다 분리하는 게 맞다고 해주셨다.

 

2. 구독 중인 레스토랑

  • 기획 의도
    • 마이 페이지에서 구독 중인 레스토랑을 한눈에 볼 수 있게 출력
  • 화면

사용자가 구독한 레스토랑들

  • 코드
class SubscribedRestaurantsAPIView(LoginRequiredMixin, View):
    def get(self, request, *args, **kwargs):
        subscribed_restaurants = Restaurant.objects.filter(subscribers=request.user).values(
            'name', 'img', 'category', 'pk', 'title')
        if subscribed_restaurants:
            json_data = {
                "subscribed_restaurants": list(subscribed_restaurants),
            }
        else:
            json_data = {
                "message": "구독 중인 레스토랑이 없습니다.",
            }
        return JsonResponse(
            json_data,
            status=HTTPStatus.OK,
        )
  • 테스트 코드
  • 어려웠던 점
  • 해결방법
  • 느낀점
    • 단순히 값을 가져오는 부분이라 간단했다.