ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 6월 27일 TIL - 전체 검색
    TIL(Today I Learned) 2023. 6. 27. 20:28

    ▷ 오늘의 배움

    📖 참조하는 모델의 필드로 필터링 할 때

    Model.objects.filter(관련된모델__필드__contains="query")

     

    ✏️ 한가지 항목에서 여러개를 필터링 할 때!

    # query = request.GET.getlist()을 사용하여 리스트 형식으로 받아올 수 있다.
    Model.objects.filter(field__in=[a,b])

    ✏️ 딕셔너리를 활용해서 필터링하기

    class APIView(View):
        def get(self, request):
        # 쿼리에 따라 필터링할 항목을 만든다.
            filter_categories = {
                'query'       : 'field__in',
                'query2'       : 'field2__in',
                ...
            }
            # request에서 필터링 값을 가져온다음 filter_categories에 있으면 키값을 이용하여 필터링할 필드와 값으로 이루어진 딕셔너리를 만든다.
            filter_set = {
                filter_categories.get(key) : value for (key, value) in dict(request.GET).items() if filter_categories.get(key)
            }
            # 필터 조건이 딕셔너리 형태이기 때문에 **언패킹을 해주어야한다.
            products = Product.objects.filter(**filter_set).distinct()

    ▷ 오늘의 시도

    💬 전체 검색을 해보자!

    처음에 검색 기능을 구현했을 때 전체 검색 없이 게시글, 태그, 장소에 대한 검색필터만 제공 했었다. 하지만 전체 검색도 필요하다 느꼈고 그를 구현하고자 하였다. 처음에는 if, elif 문으로 옵션을 구분해서 각각의 옵션에 따라 필터링을 하였다. 그래서 elif 문을 추가하여 전체 검색일 때 다시한번 필터링 코드를 작성해야하나 막막했다. 분명 뭔가 더 간단하고 좋은 방법이 있을 것 같았는데 말이다. 그래서 이리저리 살펴보던 중 전체 검색일 때 각각 옵션을 나눠줬던것을 다 한번씩 돌린다음에 중복제거를 하면 되지 않을까??? 싶은 생각이 들었다. 그래서 각각의 옵션들을 모두 if 문으로 설정해주고 조건으로 옵션이 'all'일 경우를 하나 더 주었다. 그러면 전체 검색을 할 때 각각의 필터들이 돌아가면서 게시글이 반환될테니까 말이다. 그리고 마지막에 중복된 게시글이 있을 수도 있기에 중복 제거도 한번 해주고 쿼리셋을 반환하는 방향으로 구현을 해보았다.

    def get_queryset(self):
            search = self.request.query_params.get("search")
            option = self.request.query_params.get("option")
            queryset_list = []
            # 글 검색
            if option == "article" or option == "all":
                queryset = Article.objects.filter(db_status=1)
                if search is not None:
                    queryset = (
                        queryset.filter(
                            Q(title__icontains=search) | Q(content__icontains=search)
                        )
                        .distinct()
                        .order_by("-created_at")
                    )
                    for a in queryset:
                        queryset_list.append(a)
            # 태그 검색
            if option == "tag" or option == "all":
                queryset = Tag.objects.filter(Q(db_status=1) & Q(tag__icontains=search))
                if search is not None:
                    for a in queryset:
                        taglist = a.taglist_set.all().order_by("-created_at")
                        for b in taglist:
                            if b.article.db_status == 1:
                                queryset_list.append(b.article)
            # 지역 검색
            if option == "location" or option == "all":
                search_list = search.split(" ")
                location_list = []
                queryset = MapDataBase.objects.filter(db_status=1)
                if search is not None:
                    for location in search_list:
                        queryset = (
                            queryset.filter(
                                Q(jibun_address__icontains=location)
                                | Q(road_address__icontains=location)
                            )
                            .distinct()
                            .order_by("-created_at")
                        )
                        for loc in queryset:
                            location_list.append(loc)
                    for a in list(dict.fromkeys(location_list)):
                        article_list = a.article_set.filter(db_status=1).order_by(
                            "-created_at"
                        )
                        for b in article_list:
                            queryset_list.append(b)
            # 중복 검색 값 제거
            result = []
            for i in queryset_list:
                if i not in result:
                    result.append(i)
            return result

    그리고 하나하나 역참조를 하면서 검색어를 찾았는데 오늘의 배움에 있는 방법을 활용하면 좀 더 코드가 간결하고 깔끔해 질 수 있을 것 같다. 여유가 될 때 한번 코드를 다시금 짜봐야겠다.

    댓글

Designed by Tistory.