TIL(Today I Learned)
6월 27일 TIL - 전체 검색
Hyerin P.
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
그리고 하나하나 역참조를 하면서 검색어를 찾았는데 오늘의 배움에 있는 방법을 활용하면 좀 더 코드가 간결하고 깔끔해 질 수 있을 것 같다. 여유가 될 때 한번 코드를 다시금 짜봐야겠다.