장고 Q를 활용한 필터링, 정렬, 검색 방법

2022. 2. 20. 23:16·Django
목차
  1. Q 객체 사용 방법
  2. Q를 사용한 복합 필터링
  3. 필터링 결과 정렬하기
  4. 검색 기능 구현
  5. 최종: 필터링 + 정렬 + 검색 기능

장고의 filter()에서 처리하는 키워드 아규먼트는 기본적으로 & (AND) 형식입니다. | (OR)와 같은 보다 복잡한 쿼리를 처리하려면 Q 객체를 사용할 수 있습니다. Q 객체(django.db.models.Q)는 키워드 아규먼트를 처리하기 위한 객체입니다.

Q 객체 사용 방법

Q 객체를 사용하기 위해서는 장고의 모델에서 제공하는 Q를 임포트해야 합니다.

from django.db.models import Q

각 키워드 아규먼트를 차례로 Q 객체에 넘겨줄 수 있습니다. 이때 Q 객체의 각 아규먼트는 | (OR)로 구분되지 않는 경우, & (AND)로 이어지게 됩니다.

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

한편, Q 객체를 사용하는 경우에는 Q 객체를 사용하지 않는 다른 키워드 아규먼트보다 먼저 처리되어야 합니다.

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

Q를 사용한 복합 필터링

다음과 같이 Q 객체를 사용하여 복합적인 필터링을 구현할 수 있습니다. 이는 HTTP GET 요청을 통해 파라미터와 값을 처리하고, 해당하는 값이 존재하게 될 경우, Q()에 q.add(...)를 추가하는 방식입니다. Q()는 Accomodations.objects.all()과 동일한 기능을 합니다. 마지막의 q.AND 는 q.OR이 될 수도 있으며, 이는 각 조건을 어떻게 연결 지을 지에 따라 달라집니다.

class AccommodationListView(View):
    def get(self, request, *args, **kwargs):
        try:
            accommodations = Accommodation.objects.all()

            thema_group = request.GET.getlist('themaGroup', None)
            region = request.GET.get('region', None)
            is_verified = request.GET.get('isVerified', None)
            people = request.GET.get('people', 1)
            sort = request.GET.get('sort', None)
            search = request.GET.get('search', None)

            q = Q()

            if thema_group:
                q.add(Q(themagroup__name__in=thema_group), q.AND)

            if region:
                q.add(Q(region=region), q.AND)

            if is_verified:
                q.add(Q(is_verified=is_verified), q.AND)

            accommodations = Accommodation.objects.filter(q, available_people__range=[people,30])

            (...)

코드를 자세히 보시면 조금 다른 부분들이 있습니다. 먼저, thema_group의 경우에는 하나의 값이 아닌 여러 값(예를 들면, ?themaGroup=도심&themaGroup=바다)이 들어올 수 있기 때문에 이를 GET요청에서 .getlist로 처리하고, 이와 관련된 ThemaGroup 모델의 name에 thema_group의 값으로 들어온 것이 있는지를 필터링하도록 되어 있습니다. Q(themagroup__name__in=thema_group) 부분이 바로 이러한 조건을 처리하기 위한 코드입니다.

필터링 결과 정렬하기

Q()를 통한 필터링 조건을 쿼리셋에 filter(q)와 같은 방식으로 담았다면, 이제 order_by 메소드를 사용하여 이를 간단히 정렬해볼 수 있습니다.

if sort == 'newest':
    accommodations = accommodations.order_by('created_at')
elif sort == "highest":
    accommodations = accommodations.order_by('-price')
elif sort == "lowest":
    accommodations = accommodations.order_by('price')

검색 기능 구현

검색 기능 또한 구현할 수 있습니다. GET 요청으로 serach 파라미터와 값을 받은 다음 icontains를 활용하여 검색 기능을 제공할 수 있습니다.

if search:
    accommodations = accommodations.filter(
    name__icontains = search
)

최종: 필터링 + 정렬 + 검색 기능

다음은 이상의 방법을 모두 조합하여 제가 작성했던 뷰 파일입니다. 숙소의 리스트를 필터링 요청을 따라 제공하고, 숙소 리스트에 대해 정렬 및 검색 기능을 제공합니다.

class AccommodationListView(View):
    def get(self, request, *args, **kwargs):
        try:
            accommodations = Accommodation.objects.all()

            thema_group = request.GET.getlist('themaGroup', None)
            region = request.GET.get('region', None)
            is_verified = request.GET.get('isVerified', None)
            people = request.GET.get('people', 1)
            sort = request.GET.get('sort', None)
            search = request.GET.get('search', None)

            q = Q()

            if thema_group:
                q.add(Q(themagroup__name__in=thema_group), q.AND)

            if region:
                q.add(Q(region=region), q.AND)

            if is_verified:
                q.add(Q(is_verified=is_verified), q.AND)

            accommodations = Accommodation.objects.filter(q, available_people__range=[people,30])

            if search:
                accommodations = accommodations.filter(
                    name__icontains = search
            )

            if sort == 'newest':
                accommodations = accommodations.order_by('created_at')
            elif sort == "highest":
                accommodations = accommodations.order_by('-price')
            elif sort == "lowest":
                accommodations = accommodations.order_by('price')

            accommodation_information = [
                {   
                    "id": accommodation.id,
                    "name": accommodation.name,
                    "description": accommodation.description,
                    "detail_description": accommodation.detail_description,
                    "price": accommodation.price,
                    "address": accommodation.address,
                    "region": accommodation.region,
                    "is_verified": accommodation.is_verified,
                    "latitude": accommodation.latitude,
                    "longtitude": accommodation.longtitude,
                    "check_in_time": accommodation.check_in_time,
                    "check_out_time": accommodation.check_out_time,
                    "available_people": accommodation.available_people,
                    "image_url": [images.image_url for images in accommodation.accommodationimage_set.all()],
                    "thema_group": [thema.name for thema in accommodation.themagroup_set.all()]
                } for accommodation in accommodations]

            return JsonResponse({"message": accommodation_information}, status=200)
        except:
            return KeyError({"message":"KEY_ERROR"}, status=400)

 

참고 자료:

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

반응형

'Django' 카테고리의 다른 글

장고 개발 환경에 따라 settings.py 분리하는 방법  (0) 2022.03.13
장고 get_or_create()와 race condition 문제  (0) 2022.03.05
장고에서 HTTP GET, POST 요청 처리하는 방법  (0) 2022.02.20
장고 ORM과 쿼리셋의 개념  (0) 2022.02.07
장고, 파이썬 csv 파일 처리 방법  (0) 2022.02.01
  1. Q 객체 사용 방법
  2. Q를 사용한 복합 필터링
  3. 필터링 결과 정렬하기
  4. 검색 기능 구현
  5. 최종: 필터링 + 정렬 + 검색 기능
'Django' 카테고리의 다른 글
  • 장고 개발 환경에 따라 settings.py 분리하는 방법
  • 장고 get_or_create()와 race condition 문제
  • 장고에서 HTTP GET, POST 요청 처리하는 방법
  • 장고 ORM과 쿼리셋의 개념
휘 Hwi
휘 Hwi
개발자 성장 로그
  • 휘 Hwi
    개발자 로그: 변화를 위한 공간
    휘 Hwi
  • 전체
    오늘
    어제
    • 분류 전체보기 (61)
      • 101 (1)
      • Web | Internet (4)
      • HTML | CSS (4)
      • Python (9)
      • Django (20)
      • Javascript (0)
      • Node.js (0)
      • React (0)
      • React Native (0)
      • Database (1)
      • Git (1)
      • Terminal | Vim (1)
      • Auth | Security (4)
      • AWS (0)
      • Docker (0)
      • Kubernetest (1)
      • Deployment (1)
      • Project (2)
      • TIL (12)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    JWT 디코딩
    JWT
    HTTP
    요소 절대 크기
    target="_blank"
    JWT 인코딩
    함수
    HTTP POST 요청
    HTTP GET 요청
    깃 퍼블릭 키 등록
    새 탭에서 열기
    파라미터
    장고 Views
    깃 ssh
    요소 상대 크기
    파이썬
    프로젝트 회고
    장고 URL
    탭내빙
    요소 크기 설정
    배포
    css
    장고
    TIL
    html
    깃 에러 해결
    정규 표현식
    깃 오류
    깃
    장고 프로젝트
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
휘 Hwi
장고 Q를 활용한 필터링, 정렬, 검색 방법
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.