본문으로 바로가기

쿼리의 Q 모델을 활용한 검색 기능 구현

category 장고/MTV 2019. 2. 6. 15:40

참고자료


장고문서

udemy 강의(shopping cart)



Q 객체를 사용한 복잡한 조회

부제: 검색 조건이 복잡하면 Q models 를 불러와서 정의하자.


Post.objects.filter() 는 AND 연산자가 포함이 된다. 그렇기 때문에 OR 문을 실행해야 하는 경우에는 Q objects 를 사용


[comment] 즉, A 와 B 를 포함하는 모든 검색 조건에 대해서 검색하라. 라는 것이 Q 객체를 사용하는 이유


from django.db.models import Q

Q(question__startswith='What')


Q objects 는 & 와 |(파이프라인: or 연산자) 의 사용이 가능하다. 연산자가 두 개의 Q 객체에 사용되면 새로운 Q 객체가 생성


예를 들어, 아래의 예제는 2개의 question__startswith 쿼리의 OR 을 나타내는 단일 Q 객체를 생성한다.


Q(question__startswith='Who' | Q(question__startswith='What')


이것은 아래의 SQL WHERE 절과 동일하다.

WHERE question LIKE 'Who%' OR question LIKE 'What%'


Q objects 를 & 와 |(파이프라인) 으로 결합하여 임의의 복잡성을 갖는 문장을 작성.

연산자 및 괄호 그룹화를 사용하는데, Q objects 는 '~' 연산자를 사용하여 무효화할 수 있으므로 일반 쿼리와 부정(NOT) 쿼리를 결합한 조회를 허용


Q(question__startswith='Who' | ~Q(pub_date__year=2005)


키워드 인수(filter(), exclude(), get()) 을 사용하는 각 조회 함수는 하나 이상의 Q objects 를 위치 지정되지 않은 인수로 전달할 수 있다.

조회 함수에 여러 개의 Q objects 인수를 제공하면 인수가 AND 가 된다.


Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))


SQL 문으로 작성

SELECT * from polls WHERE question LIKE 'Who%'
   AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')


조회 함수(Lookup functions) 는 Q objects 와 키워드 인수의 사용을 혼합할 수 있다.

조회 함수에 제공된 모든 인수(키워드 인수 또는 Q objects) 는 함께 AND 된다.

그러나 Q objects 가 제공되면 키워드 인수의 정의 앞에 와야 한다.


[comment] (1순위) 모든 조건에 해당하는 검색조건 (2순위) 연산자가 들어간 상세 조건


# 올바른 예시

Poll.objects.get(
   question__startswith='Who',
   Q(pub_date=date(2005, 5, 2) | pub_date=date(2005, 5, 6)),
)


# 잘못된 예시

# INVALID QUERY
Poll.objects.get(
    Q(pub_date=date(2005, 5, 2) | pub_date=date(2005, 5, 6)),
    question_startswith='Who',
)



강의를 통해 실제 적용한 예시

- 쉬운 이해를 위해 실제 적용한 예시를 변형



shop/base.html

- 메인 페이지에서 name='q' 에 대한 객체를 받아 search.html 에서 검색결과를 보여줌

<#form method="GET" action="{% url 'search_app:search_result %}">
    {% csrf_token %}
    <# input type="search" name="q">
    <# button type="submit">찾기
<#/form>



search_app/search.html

- base.html 에서 입력 -> search 템플릿에서 검색 결과를 보여줌

{% for product in products %}
    {{ product.name }}
    {{ product.price }}
{% empty %}
    검색결과: 0개의 상품
{% endfor %}


search_app/urls.py

from . import views

urlpatterns = [
    path('', views.search_result, name='search_result)
]


search_app/views.py

- if 'q' in reuqest.GET : form 에서 GET 요청으로 q(검색어) 를 입력했다면,

- query 에 해당 objects 를 담고 -> Product 의 모델에서 일치하는 조건만 렌더 시킨다

from django.shortcuts import render

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

def search_result(request):
    query = None
    products = None

    if 'q' in request.GET:
        query = request.GET.get('q')
        products = Product.objects.all().filter(Q(name__contains="query") | Q(description__contains="query"))
    return render(request, 'search_app/search.html', {'query': query, 'products': products}



'장고 > MTV' 카테고리의 다른 글

try, except 와 if else 를 써야할 때  (0) 2019.03.14
AbstractBaseUser 모델  (0) 2019.03.01
구문 분석 오류(could not parse ...)  (1) 2019.02.20
redirect 기능  (0) 2019.02.19
장고 폼(bound form, unbound form, cleaned_data, is_valid)  (0) 2019.01.21