Django project # 2

minch·2021년 8월 10일
0

Django

목록 보기
14/16
post-thumbnail

리스트 필터링

제품 리스트를 get으로 주기 위하여 Query parameter를 사용하여 필터링 처리를 하기로 하였다.

class ProductsView(View):
    def get(self, request):
        category_id    = request.GET.get('category') 
        subcategory_id = request.GET.get('subcategory')
        tags           = request.GET.getlist('tag')
        sort           = request.GET.get('sort')
        
        if category_id:
            products = Product.objects.filter(sub_category__category=category_id)

        if subcategory_id:
            products = products.filter(sub_category=subcategory_id)
        
        if tags:
            products = products.filter(tags__name__in=tags)
       
        if sort:
            products = products.annotate(price=Min(option__price)).order_by(sort)

위와 같은 방식으로 Query parameter로 받아올때 실행되게 만들어 주었다.

tag 같은 경우에는 한번에 여러 값을 받아올 수 있기 때문에, getlist로 list 형태로 받아오게 만들었다.

하지만 이렇게 하나씩 필터링 하는 방법보다 더 좋은 Q객체의 활용법이 있다.

Q 객체 활용

Q 객체란?

django orm에서 쿼리문처럼 and, or 과 같은 조건을 쓰고 싶을때 사용할 수 있다.

sql 쿼리문

select * from product where sub_category=스킨 and tags=new

Q 객체 사용

Product.objects.filter(Q(sub_category='스킨') & Q(tags='new'))

&를 사용하면 and 조건이고,
|를 사용하면 or 조건이다.

그래서 이 Q객체를 활용하여 if문과 아래와 같이 사용할 수 있다.

class ProductsView(View):
    def get(self, request):
        category_id    = request.GET.get('category') 
        subcategory_id = request.GET.get('subcategory')
        tags           = request.GET.getlist('tag')
        sort           = request.GET.get('sort')

        product_filter = Q()

        if category_id:
            product_filter.add(Q(sub_category__category=category_id), Q.AND)

        if subcategory_id:
            product_filter.add(Q(sub_category=subcategory_id), Q.AND)
            
        if tags:
            product_filter.add(Q(tags__name__in=tags), Q.AND)
             
        products = Product.objects.filter(product_filter)
        
        if sort:
            products.annotate(price=Min('option__price')).order_by(sort)

이렇게 사용을 해보니 category, subcategory, tag 들 간에는
AND 조건으로 필터링이 잘 이루어지지만 여러개의 tag를 받았을 때,
tag들 간에는 AND 조건이 아닌 OR 조건으로 이루어진다.

또, sort안에 내용이 안담겨 올때나 알 수 없는 필터링이 이루어 졌을 때를 대비하여
dictionary를 만들어서 sort의 이름을 정의해주고, 정렬 기준의 default 값을 설정해 주어야 한다.

그리하여 최종 수정본은 아래와 같다.

class ProductsView(View):
    def get(self, request):
        category_id    = request.GET.get('category') 
        subcategory_id = request.GET.get('subcategory')
        tags           = request.GET.getlist('tag')
        sort           = request.GET.get('sort')

        product_filter = Q()
        
        sort_by = {
            'name'      : 'name',
            'low_price' : 'price',
            'high_price': '-price'
        } # 이름을 정의해주는 dict를 만들어주고,
        
        if category_id:
            product_filter.add(Q(sub_category__category=category_id), Q.AND)

        if subcategory_id:
            product_filter.add(Q(sub_category=subcategory_id), Q.AND)
             
        products = Product.objects.filter(product_filter).annotate(price=Min('option__price'))
                   .order_by(sort_by.get(sort, "name"))
                   # sort_by에 해당하는 값이 없으면 default인 'name'으로 정렬
        
        if tags:
            for tag in tags:
                products = products.filter(tags__name=tag)
                # AND 조건으로 만들기 위해 하나씩 뒤로 붙여서 필터링

0개의 댓글