Django Q 객체 정리

개발자 강세영·2022년 6월 3일
0

TIL

목록 보기
36/70
post-custom-banner

Q객체란 장고에서 제공하는 기능으로 SQL로는 WHERE AND, OR, NOT 조건을 추가해주는 것이다. Q객체를 활용하면 복잡한 필터링을 편하게 실행할 수 있다. 대체로 filter()에 가장 많이 활용되는 듯하나 exclude(), get()에도 쓸 수 있다.

임포트문은 다음과 같다.
from django.db.models import Q

보통 빈값의 Q객체 변수를 먼저 만들고, 밑에서 조건에 맞게 내용을 추가하는 식으로 많이 활용하는 듯하다.

q = Q()
q.add(Q(options__name="1개입"), q.AND)
q &= Q(options__name="1개입")

위 코드에서 q.add문과 q &= 문의 내용은 같다. AND 조건으로 추가되는 것이다. 교집합 같은 것이다.

q = Q()
q.add(Q(thumbnail_url__in='http'), q.OR)
q |= Q(thumbnail_url__in='http')

위 코드 또한 q.add문과 q |= 문의 내용은 같다. OR 조건으로 추가되는 것이다. 합집합 같은 것이다.

빈 Q객체에 처음 더하는 것은 첫번째 값이라 AND OR의 조건이 지정되지 않는 듯 하다.
두번째 부터는 조건이 지정된다.

Q객체로 NOT 조건을 실행하려면 두가지 방법이 있다.
exclude()를 이용하거나 ~Q() 같이 Q자 앞에 ~를 더해주는 것이다.

Product.objects.exclude(name__contains='바른')
q &= ~Q(thumbnail_url__contains='http')
이런식으로 NOT 조건을 실행하는데 사용할 수 있다.
class ProductListView(View):
    def get(self, request):
        category = request.GET.get('category', None)
        search   = request.GET.get('search', None)
        sort     = request.GET.get('sort')
        offset   = int(request.GET.get('offset', 0))
        limit    = int(request.GET.get('limit', 6))

        q = Q()
        q &= Q(options__name=ProductOptionEnum.ONE.value)

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

        if search:
            q &= Q(name__contains=search)

        sort_set = {
            "name"  : "name",
            "-name" : "-name",
            "old"   : "created_at",
            "new"   : "-created_at",
            "price" : "options__price",
            "-price": "-options__price",
            "review": "-review_count",
            "sales" : "-sales_sum",            
        }
        sort = sort_set.get(sort, 'name')
        
        products = Product.objects.filter(q).order_by(sort).distinct()[offset:offset+limit]

위 코드는 제품 목록을 조건에 맞게 조회하는 장고 View이다.

  • 카테고리, 제품명 검색어를 쿼리 파라미터로 받는데, 이 값들이 있다면 빈 Q객체에 추가되고 마지막에 filter(q)로 적용된다.
  • 만약 Q객체에 들어오는 값이 없어서 빈 Q객체가 filter()에 들어간다고 해도 에러가 나지 않고 objects.all()과 같아진다.

자료출처
https://docs.djangoproject.com/ko/4.0/topics/db/queries/#complex-lookups-with-q
https://velog.io/@jxxwon/Django-Q-%EA%B0%9D%EC%B2%B4

post-custom-banner

0개의 댓글