-
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
그리고 하나하나 역참조를 하면서 검색어를 찾았는데 오늘의 배움에 있는 방법을 활용하면 좀 더 코드가 간결하고 깔끔해 질 수 있을 것 같다. 여유가 될 때 한번 코드를 다시금 짜봐야겠다.
'TIL(Today I Learned)' 카테고리의 다른 글
6월 29일 TIL - 페이지네이션 오류, html 내용 입력 수정 (0) 2023.07.03 6월 28일 TIL - 사용자 피드백 (0) 2023.06.29 6월 26일 TIL - 장고 어드민 커스터마이징 (0) 2023.06.26 6월 23일 TIL - 중간발표 준비 (0) 2023.06.25 6월 22일 TIL - 내 위치 기준 거리 검색 (0) 2023.06.23