본문 바로가기

프로젝트/미술관 뒤 백엔드 지금은 전시상황

최종 팀 프로젝트[back] 통합 검색 filter

https://github.com/sdoram/b4_exhibitions_backend

 

GitHub - sdoram/b4_exhibitions_backend: B4조 지금은 전시상황 백엔드

B4조 지금은 전시상황 백엔드 . Contribute to sdoram/b4_exhibitions_backend development by creating an account on GitHub.

github.com

 filter에서 or가 필요함 

1. django Q 사용

from django.db.models import Q

 

장점 : django를 잘 이해하고 있다면 코드의 가독성이 크게 증가할 것 같음 

단점 : 이해도가 높지 않다면 가독성에 악영향 끼칠 가능성 있음 

결론 : 현재 프로젝트 구조상 중복해서 사용할 가능성이 높지 않으므로 | 를 통해서 처리하는 게 좋을 것 같다.

 

여러 모델의 filter 결과를 하나의 return에서 보여줘야 함 

2. 전용 serializer 선언하기 

장점 : views에서 가독성 증가 

단점 : serializer 구성을 위한 시간 소요 

결론 : 차후 수정의 여지가 있지만 지금은 views에서 처리하자.

 

1. return에 여러 모델의 filter 결과를 보여주기

 문제점

return에 여러 모델의 filter 결과를 보여줘야 함 

 시도해 본 것들

exhibitions = Exhibition.objects.all()
reviews = Review.objects.all()
accompanies = Accompany.objects.all()
            
results = (
	    ExhibitionSerializer(exhibitions, many=True),
            ReviewSerializer(reviews, many=True),
            AccompanySerializer(accompanies, many=True),
        )
        
return Response([result.data for result in results], status=status.HTTP_200_OK)

filter 없이 각각의 models를 불러오고 Response에서 한 번에 확인하기가 가능한 것을 확인했다. 

 

filter에 or 조건 걸기 

from django.db.models import Q 사용하기

 

exhibitions = Exhibition.objects.filter(
                Q(content__icontains=search) | Q(info_name__icontains=search)
            ).order_by("-created_at")

조건을 중복해서 설정하고 싶을 때 Q를 통해서 사용할 수 있다. 

 

Q 없이 구현하기  

exhibitions = Exhibition.objects.filter(
                content__icontains=search
            ) | Exhibition.objects.filter(info_name__icontains=search).order_by(
                "-created_at"
            )

여러 field를 거친다면 코드가 길어지겠지만, 아직 2개의 field만 확인하고 이 코드 말고 다른 곳에서 Q를 사용할 곳이 없기 때문에 | 를 통해서 or 조건 설정 

 해결 방법

class ExhibitionSearchView(APIView):
    def get(self, request):
        search = request.query_params.get("search", None)
        # 키워드가 있는 경우
        if search:
            # 전시회 내용 or 제목으로 검색
            exhibitions = Exhibition.objects.filter(
                content__icontains=search
            ) | Exhibition.objects.filter(info_name__icontains=search).order_by(
                "-created_at"
            )
            reviews = Review.objects.filter(content__icontains=search).order_by(
                "-created_at"
            )
            accompanies = Accompany.objects.filter(content__icontains=search).order_by(
                "-created_at"
            )
        else:
            exhibitions = Exhibition.objects.all().order_by("-created_at")
            reviews = Review.objects.all().order_by("-created_at")
            accompanies = Accompany.objects.all().order_by("-created_at")
        results = (
            ExhibitionSerializer(exhibitions, many=True),
            ReviewSerializer(reviews, many=True),
            AccompanySerializer(accompanies, many=True),
        )
        # serializer.data의 리스트를 Response로 보내주기
        return Response([result.data for result in results], status=status.HTTP_200_OK)

 알게 된 점

Response에 담을 수 있는 정보는 꽤 유연한 것 같다. 

 

2. 검색 결과에 pagination 기능 추가 

 문제점

class ExhibitionSearchView(APIView):
    def get(self, request):
        search = request.query_params.get("search", None)
        pagination = CustomPageNumberPagination()
        # 키워드가 있는 경우
        if search:
            # 전시회 내용 or 제목으로 검색
            exhibitions = Exhibition.objects.filter(
                content__icontains=search
            ) | Exhibition.objects.filter(info_name__icontains=search).order_by(
                "-created_at"
            )
            reviews = Review.objects.filter(content__icontains=search).order_by(
                "-created_at"
            )
            accompanies = Accompany.objects.filter(content__icontains=search).order_by(
                "-created_at"
            )
        else:
            exhibitions = Exhibition.objects.all().order_by("-created_at")
            reviews = Review.objects.all().order_by("-created_at")
            accompanies = Accompany.objects.all().order_by("-created_at")
        paginated_exhibitions = pagination.paginate_queryset(exhibitions, request)
        paginated_reviews = pagination.paginate_queryset(reviews, request)
        paginated_accompanies = pagination.paginate_queryset(accompanies, request)
        results = (
            ExhibitionSerializer(paginated_exhibitions, many=True),
            ReviewSerializer(paginated_reviews, many=True),
            AccompanySerializer(paginated_accompanies, many=True),
        )
        # serializer.data의 리스트를 Response로 보내주기
        return Response(
            [pagination.get_paginated_response(result.data) for result in results],
            status=status.HTTP_200_OK,
        )

pagination을 검색 결과에도 확인할 수 있도록 만들었지만, 각 검색 별로 독립적이지 않아서 하나의 페이지를 넘길 때 다른 검색 결과의 페이지도 넘어가는 형태가 됐다. 

 

하나의 view로 검색을 처리하되 중간에 검색 조건을 추가로 설정해서 하나의 model만 검색할 수 있도록 변경하는 게 좋을 것 같다.