Django project # 2


フィルタリスト
製品リストに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形式で受信させる.
しかし、このように1つずつフィルタリングする方法よりも良いQオブジェクトの使い方があります.
Q利用対象
Q対象とは?
django ormでは、and、orなどの条件をクエリー文のように使用できます.
sqlクエリ文select * from product where sub_category=스킨 and tags=newQ使用対象Product.objects.filter(Q(sub_category='스킨') & Q(tags='new')) &が使用される場合は、和条件です.|を使用する場合は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)
このように使用すると、categorysubcategorytagの間に
AND条件下での濾過は良好であったが、tagが複数受信された場合には良好であった.tag間はAND条件ではなくOR条件です.
また、sortにコンテンツがない場合や、未知のフィルタリングが行う場合、
dictionaryを作成してsortの名前を定義し、ソート基準のデフォルト値を設定する必要があります.
したがって、最終改訂本は以下の通りである.
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 조건으로 만들기 위해 하나씩 뒤로 붙여서 필터링