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이다.
자료출처
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