Django 프로젝트 - 2주차_2

9532 단어 pythonORMdjangoORM

오늘은 저번주에 추가한 냉장고 파먹기 검색기능에 대해 기록한다.

먼저 내가 원하는 프로세스는 가지고있는 재료를 입력하면 해당 재료들로 만들 수 있는 요리들을 알려주는 것이다.

위 내용을 구현해보기 위해 다음과 같이 시도했다.

  1. 레시피에서 필요한 재료들을 string으로 공백없이 ','로 구분해 입력했다.
  2. 검색할때 내가가진 재료도 ','로 구분하여 여러개를 입력한다.
    예를들어 검색창에 계란,밥,돼지고기,파,김치 를 입력한다.
  3. 그러면 아래와 같은 상황일때 이렇게 결과를 출력해준다.
  • 레시피 1 필요한 재료 : 돼지고기,김치
  • 레시피 2 필요한 재료 : 계란,밥
  • 레시피 3 필요한 재료 : 소고기,파,김치
  • 레시피 4 필요한 재료 : 밥,계란,김치

사이트에 위 3개 레시피가 등록되있다고 생각해보자.
내가 가지고 있는 재료를 계란,밥,돼지고기,파,김치 라고 입력했다.
레시피1, 레시피2, 레시피4의 경우 재료들이 내가 가진 재료안에 모두 존재한다. 3의 경우 파,김치는 있지만 소고기가 없으므로 만들 수 없다고 간주한다.

그러므로 검색 결과값으로 레시피1,2,4을 제외하고 출력한다.

기존 recipe_list를 나타내는 함수를 수정하여 ORM 덕분에 좀 더 쉽게 만들 수 있었다.

먼저 검색을 하기 위한 검색창을 만들었다.

templates/search_box.html

<!-- 검색창 -->
        <div class="row justify-content-end">

            <div class="col-4 input-group">
                <select class="form-control sr" style="width:50px">
                    <option value="name" {% if sr == 'name' %}selected{% endif %}>요리 이름</option>
                    <option value="need_ingredient" {% if sr == 'need_ingredient' %}selected{% endif %}>재료</option>
                </select>
                <span class="input-group-append">
                    <input type="text" class="form-control kw" value="{{ kw|default_if_none:'' }}">
                </span>
                </div>
                <span class="input-group-append">
                    <button class="btn btn-outline-dark" type="button" id="btn_search">검색하기</button>
                </span>
        </div>
        <br>

검색창의 검색 기준을 정하기위해 셀렉트 박스를 이용해 요리(레시피)이름, 재료로 총 2가지 옵션을 주었다.

그 다음으로 검색할 내용을 입력받는 검색박스, 검색하기 버튼을 만들었다.

이렇게 나온다.

다음은 셀렉트 박스와 검색결과에 따라 레시피 리스트를 출력해줘야한다.

naengpa/views.py

kw = request.GET.get('kw','')
sr = request.GET.get('sr','name') # 검색 기본필터 요리이름
# kw (입력키워드), sr(검색 기준(셀렉트박스)), name(셀렉트 박스 default 값)

recipe_list = Recipe.objects.all().order_by('-create_date')\
        .annotate(reviews_count = Count('review'))\
        .annotate(score_avg=Round(Avg('review__score')))
# 기존 레시피들을 모두 불러온다.

    if kw: # 검색 키워드가 들어오면 셀렉트 박스 상태를 확인

        if sr=='need_ingredient': # 재료로 검색하기
        	sp_kw = kw.split(",") # 검색할 재료 입력 재료구분은 공백없이 ,로 입력받기.
            query = Q() # Django ORM Where 절에 or 문을 추가하고 싶을때 사용
            
            for i in recipe_list: # 레시피 리스트들중에서
                ingre_check = False # 재료 여부 체크
                sp_ingre = i.need_ingredient.split(",") # 해당 레시피의 재료를 ,기준으로 쪼개기
                if len(sp_ingre)<=len(sp_kw): # 가진 재료개수보다 레시피 재료개수가 많으면 계산필요 없음.
                	for j in sp_ingre:
                    	if j not in sp_kw: # 해당 레시피 재료중 하나라도 sp_kw에 없으면 만들기 불가능.
                        	ingre_check = True
                        	break # 부족한 재료가 있으므로 더이상 살펴 볼 필요 없음.
                        
                	if ingre_check==False: # for j in sp_ingre를 모두 돌았으나, False라면 모든 재료를 가지고 있음.
                    	query = query | Q(id=i.id) # 해당 id를 가진 레시피를 or로 더해나가기
                    
            recipe_list = recipe_list.filter(query) # filter로 적용해 출력
            
        else: # 요리 이름으로 검색
            recipe_list = recipe_list.filter(Q(name__icontains=kw)) # 해당 키워드가 name값에 포함되면 출력

쿼리에 대해서 어떻게 짜야할지 얘기를 나누며 다음과 같은 고민들을 했었다.

  1. 정렬 후 in을 이용해보자 : 정렬 했는데 중간에 다른재료가 껴있으면 False가된다.
    ex) a="1,3,6,8" b="1,3" c="3,8"
    b in a는 True다. 그러나 c가 가진값들이 모두 a에 있지만 c in a는 False다. 재료의 순서가 똑같아야 하므로 이 방법으로는 불가능하다.

  2. set을 이용해 정렬 후에 &로 비교하자 set(검색재료) & set(레시피재료) : 레시피에 부족한 재료가 있을 경우 걸러낼 수 없었다.

  3. 내가 가진 재료를 각 레시피와 일일이 비교하자.

일단 내가 의도한 기능을 만들 수 있기 때문에 3번 방법을 선택했고 다행히 의도한대로 결과를 가져온다.

그런데 막상 해보니 몇가지 문제를 느꼈다.

  1. 속도가 느릴 것 같다.
    레시피 개수 * 각 레시피 재료 개수만큼의 연산이 필요하다. 레시피 개수가 늘어날수록 속도는 훨씬 더 느려질듯.. 하지만 촌각을 다투어야 하는 서비스는 아니니 사용하는데에는 큰 지장이 없을수도??
    물론 더 좋은 방법이 생각나면 바꿀 것이다.

  2. 검색 재료의 범위를 어디까지 두어야 하는가?
    내가 레시피를 검색 할때는 메인재료를 기준으로 찾은 뒤, 각 재료들을 확인하고 모두 있으면 만들게 된다.
    그러나 레시피를 찾아도 없는 재료가 자꾸 튀어나와 적절한 요리를 찾는 시간이 꽤 걸렸다. 그래서 가지고 있는 재료가 있을때 이걸로 뭘 해먹을 수 있을지 바로 알려줬으면 좋겠다 싶은게 이 사이트를 만들기 시작한 계기였다.
    그래서 이 부분은 매우 중요한 문제다. 단순히 재료들을 나열해 입력한다 생각했었는데 검색기능을 일부 구현하고 사용해보니 어디까지 재료로 입력받아야 할지 고민이 생겼다.
    간장, 설탕, 참기름, 마늘 등 양념이나 향신료도 다 일일이 적어야할까??
    돼지고기, 소금, 설탕, 간장, 참기름, 마늘, 다시다 이렇게??
    직접 사용해보면서 개선해 나가는 수 밖에.

생각보다 스무스하게 진행 되어서 좋았는데, 프로그래밍 부분도 아닌 생각지도 못한 부분에서 큰 고민거리가 생겼다.

재화를 받으며 그에 응당한 서비스를 제공하는 회사(분)들이 얼마나 대단한지 새삼 느끼게된 경험이였다.

좋은 웹페이지 즐겨찾기