Project1- 상품 정렬기능 효율적 코드

Heechul Yoon·2020년 3월 2일
0

LOG

목록 보기
23/62

상품 정렬 기능

여기서 구현한 상품 정렬기능의 코드를 좀 더 효율적으로 짜보자. 이전에 짰던 코드는 다음과 같다.

class ProductView(View):
    def get(self, request, *args, **kwargs):
        sort_by = request.GET.get('sort_by', None)
        product_info = Product.objects.select_related('harvest_year', 'measure').values(
                'name',
                'price',
                'small_image',
                'harvest_year__year',
                'measure_id__measure',
                'is_on_sale',
                'is_in_stock',
        )

        if sort_by == 'title-ascending':
            name_ascending = product_info.order_by('name')
            return JsonResponse({'data' : list(name_ascending)}, status = 200)

        elif sort_by == 'title-descending':
            name_descending = product_info.order_by('-name')
            return JsonResponse({'data' : list(name_descending)}, status = 200)

        elif sort_by == 'price-ascending':
            price_ascending = product_info.order_by('price')
            return JsonResponse({'data' : list(price_ascending)}, status = 200)

        elif sort_by == 'price-descending':
            price_descending = product_info.order_by('-price')
            return JsonResponse({'data' : list(price_descending)}, status = 200)

        return JsonResponse({'data' : list(product_info)}, status = 200)

이와같이 들어온 query parameter을 로직으로 처리할경우 if문을 계속 반복해야한다.

이런경우 query parameter을 GET에 넣어줄 때 부터 정렬 매서드의 정렬기준으로 쓰이는 문자열로 보내주면 된다.

<order by에 들어갈 기준>
name : 이름순
-name : 이름 역순
price : 가격순
-price : 가격 역순

https://foodly-store.myshopify.com/collections/all-products/?sort_by=-price

위의 경우는 query parameter의 value값으로 price정렬 역순 문자열을 보냈다.
이제 받은 정렬 기준을 바로 사용해보자.

class ProductView(View):
    def get(self, request):
        sort_by = request.GET.get('sort_by', 'id')
        offset   = int(request.GET.get('offset', 0))
        limit    = offset + 12
        product_info = Product.objects.select_related('harvest_year', 'measure').order_by(sort_by).values(
                'name',
                'id',
                'price',
                'small_image',
                'harvest_year__year',
                'measure_id__measure',
                'is_on_sale',
                'is_in_stock',
        )[offset:limit]

        return JsonResponse({'data' : list(product_info)}, status = 200)

위와 같이 GET으로 들어온 정렬 기준을 바로 order_by안에 넣어서 쿼리를 날려준다. 첫번째 코드처럼 if문을 하나하나 적어줄 필요 없이 가져온 value값이 기준이 되기 때문에 기준이 들어온 경우와 들어오지 않은 두가지 경우만 생각해서 코드를 작성해주면 된다.

ManytoMany + OnetoOne 쿼리줄이기

상품상세페이지 에서는 1대1의 관계에 있는 정보들(타이틀, 제품설명, 영양정보)와 다대다관계에 있는 정보(유사상품 정보)가 같이 들어가 있다. 이 경우 1대1의 경우는 하나의 객체를 가져오고, 다대다의 경우는 여러개의 객체를 가져와야 하기 때문에 두번의 쿼리를 해야한다고 생각 할 수 있다.

prefetch_related와 select_related를 사용하면 한번의 쿼리로 위의 두가지 경우를 해결 할 수 있다.

class ProductDetailView(View):
    def get(self, request, product_id):
[1]     data_caching = Product.objects.filter(id=product_id).select_related('measure', 'harvest_year').prefetch_related('similar_product')         

[2]     product_info = data_caching.values(
                'name', 
                'harvest_year_id__year',
                'is_in_stock', 
                'measure_id__measure',
                'description',
                'price', 
                'small_image',
                'big_image',
                'energy', 
                'carbonydrate',
                'protein',
                'fat', 
                'mineral',
                'vitamin',
                'similar_product__name'
        )
[3]     similar_product = data_caching[0].similar_product.values(
                'name',
                'harvest_year_id__year',
                'is_in_stock',
                'measure_id__measure'
        )
        return JsonResponse({'data' : {'product_info' : list(product_info), 'similar_product' : list(similar_product)}}, status = 200)

[1]에서와 같이 select_related로 1대1의 관계에 있는 테이블을, prefetch_related를 사용하여 다대다 관계에 있는 테이블을 caching한다.

그리고 [2]와 [3]에 나누어 caching된 테이블에서 값을 가져온다.

profile
Quit talking, Begin doing

0개의 댓글