Django Q 객체

신지원·2021년 4월 21일
6
post-thumbnail

Q 객체

장고 orm에서 쿼리문처럼 or 조건을 쓰고 싶을때 사용할 수 있다.

#sql 쿼리문
select * from product where category=소 or sub_category=등심

# 장고 orm
Product.objects.filter(Q(category=소) | Q(sub_category=등심))

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

where 조건 and 조건 => 조건 둘다를 만족하는 결과값만 보여준다. 즉 교집합
where 조건 or 조건 => 조건들중 하나라도 조건에 맞으면 그 결과 값을 전부 다 보여준다. 즉 합집합

Q()

from django.http      import JsonResponse
from django.views     import View

from products.models  import Product
from django.db.models import Q

class ProductListView(View):
    def get(self, request):
        category     = request.GET.get('category', None)
        sub_category = request.GET.get('sub_category', None)
        pick         = request.GET.get('pick', None)
        discount     = request.GET.get('discount', None)
        new          = request.GET.get('new', None)

        q = Q()

        if category:
            q &= Q(sub_category__category__name=category)

        if sub_category:
            q &= Q(sub_category__name=sub_category)

        if pick:
            q &= Q(sub_category__category__name=pick)

        products = Product.objects.filter(q)

        if discount:
            products = products.order_by('-discount_rate')[:6]

        if new:
            products = products.order_by('-created_at')[:4]

        result = [{
                    'id'           : product.id,
                    'created_at'   : product.created_at,
                    'name'         : product.name,
                    'image_url'    : [product_image.image_url for product_image in product.productimage_set.all()],
                    'price'        : int(product.get_real_price()['real_price']),
                    'real_price'   : int(product.original_price),
                    'discount_rate': int(product.discount_rate),
        } for product in products]

        return JsonResponse({'result': result}, status=200)

위는 전체적인 내 코드이고, 아래는 Q를 사용한 부분이다.

&= , |= 사용하는 경우

q = Q()  

        if category:
            q &= Q(sub_category__category__name=category)

        if sub_category:
            q &= Q(sub_category__name=sub_category)

        if pick:
            q &= Q(sub_category__category__name=pick)

        products = Product.objects.filter(q)

Q() 은 Product.objects.all() 과 똑같다.
Product 전체를 변수에 담아두고, q변수 안에 조건들을 넣어주는 느낌!
즉, q &= Q(sub_category__category__name=category)는 q라는 변수안에 조건들을 하나하나 넣어주고 마지막 filter에 그 변수를 넣어서 쿼리를 한번만 날려도 되도록 해준다.

변수 q에 맞지 않은 조건이 들어왔을 경우에는, all()로 Products 전부를 가져온다.

직접 http 문을 날려보면서 확인 해봤다.
http GET localhost:8000/products discount==1 로 key discount를 넣어줬을때 print문으로 찍어본 결과는 다음과 같다..

discount의 value값이 들어왔을 경우에, if discount: 까지 내려가기전 print 문을 찍어보니
Product테이블의 전체의 상품이 나온것을 확인 할 수 있었다.

if discount: 조건문에 한번 걸치고 난뒤, 다시 products 변수에 어떤 값들이 담아져 있는지 확인해보니 할인율 순으로 6개의 제품들만 products 변수에 담겨 있는 모습을 확인 할 수있었다...!

💡 쿼리를 적게 날릴 수록 데이터 베이스에 부담이 덜 가서 좋다.

add를 사용하는 경우

첫번째로 Q를 선언하고 .add()로 추가할때 두번째 인자값은 and, or 둘중 어느것으로 연결할지 나타내고, 여기에 선언된 값으로 앞의 값과 연결된다.
비어있는 Q객체에 조건을 넣어주는데 뒷부분에 이런식으로 connector를 사용 할 수있다.

💡 주의할점!!
add로 조건을 합치든, &=, |=를 사용하든 두번째에 오는 and, or이 앞과 뒤의 조건을 연결한다.
sub_category의 조건을 바꾸어 주니깐 and와 or이 바뀌는 모습이 확인된다.

category의 조건을 바꿔준다고 해서 and가 or로 바뀌지 않는다.


and or 자꾸 헷갈림..

이게 &를 사용 했을 때 (교집합)
이게 |를 사용 했을 때 (합집합)

0개의 댓글