Django GET 검색시 MultiValueDictKeyError 해결

2020. 10. 03 IT/컴퓨터 > Django

간단한 Django 트러블슈팅 하나 포스트.

 

view 를 작성하다 보면 폼에서 GET 메소드를 이용하여 결과를 받아 처리해서 페이지를 표시해줄 일이 종종 있다. 주로 블로그의 글 등 어떤 object들의 검색 결과를 받아 표시해줄 때이다.

이때 GET 으로 전달된 파라미터가 있는 경우에는 해당하는 파라미터를 전달받아 필요한 처리를 해서 템플릿을 띄워 주고, 파라미터가 전달되지 않은 경우에는 기본 페이지를 보여주는 등의 처리를 하게 된다.

 

GET method로 폼을 제출하면 제출된 값들은 request.GET 객체에 딕셔너리 형태로 전달되게 된다 (정확히는 파이썬 딕셔너리가 아닌 장고 고유의 QueryDict 객체임).

 

예를 들어 블로그의 포스트를 검색하기 위한 다음과 같은 폼이 있다면 

[ post_search.html ]
<form method="GET" action="{% url 'post_search' %}">
    <select name="post_search_type" id="post_search_type">
        <option value="title" selected>제목</option>
        <option value="title_and_content">제목+내용</option>
        <option value="author_username">작성자 ID</option>
        <option value="author_nickname">작성자 닉네임</option>
    </select>
    <input name="post_search_keyword" id="post_search_keyword">
    <button type="submit">검색</button>
</form>

 

검색 버튼을 르면 각각 입력 필드의 name 인 post_search_type 과 post_search_keyword 를 key로, 사용자가 입력한 값을 value로 갖는 request.GET 객체가 생성된다. 예를 들어 option을 제목(title) 로 선택하고 'test' 라는 키워드로 검색을 한다고 할 때, 

해당 작업을 처리하는 views.py 에서 request.GET을 출력해보자.

[ views.py ]
def post_search(request):
    template_name = 'post_search.html"
    print(request.GET)

    ... 이하 생략 ...

 

터미널에 다음과 같이 나올 것이다.

<QueryDict: {'post_search_type': ['title'], 'post_search_keyword': ['test']}>

 

그래서 각각의 키에 해당하는 작업을 처리하기 위해서는 request.GET['post_search_type'] 혹은 request.GET['post_search_keyword'] 식으로 해당하는 값을 불러와서 처리를 해 주면 된다.

 

[ views.py ]
def post_search(request):
    template_name = 'post_search.html"
    context = {}
    
    post_search_type = request.GET['post_search_type']
    post_search_keyword = request.GET['post_search_keyword']

    ''' 키워드와 검색 방법을 가지고 해당하는 검색 결과를 출력해주기 위한 logic '''

    return render(request, template_name=template_name, context=context)

 

그런데 이 때 문제가, 폼에 아무 값이 전달되지 않고 페이지가 처음으로 로딩되는 경우, 혹은 query 값이 없이 url 을 통해 직접 페이지에 접근하는 경우에는 아직 QueryDict에 해당하는 key 값과 value가 생성되지 않은 상태이다. 이 상태에서 request.GET['post_search_type'] 또는 request.GET['post_search_keyword'] 의 값을 변수에 할당하려고 하면 다음과 같이 MultiValueDictKeyError 가 발생하게 된다.

 

 

(settings.py 에서 DEBUG = True 로 해 놓은 상태에서는 이렇게 에러 내용이 보이고, DEBUG = False 인 상태에서는 Internal Server Error (500) 으로 표시될 것이다.)

 

이를 방지하기 위해서 바로 QueryDict 의 키 값을 부르는 대신 다음과 같이 request.GET.get() 메서드를 이용할 수 있다. 

[ views.py ]
def post_search(request):
    template_name = 'post_search.html"
    context = {}
    
    post_search_type = request.GET.get('post_search_type')
    post_search_keyword = request.GET.get('post_search_keyword')

    ''' 키워드와 검색 방법을 가지고 해당하는 검색 결과를 출력해주기 위한 logic '''

    return render(request, template_name=template_name, context=context)

 

이렇게 하면 get() 안에 전달한 키 값으로 QueryDict에 해당하는 key와 value 가 있는지 찾아서, key가 있는 경우에는 그 key의 value 값을 반환해주고, key를 찾지 못한 경우에는 에러를 일으키지 않고 None을 반환해 준다. 

None이 반환된 경우에는 아직 검색 키워드가 입력되지 않은 상태임을 의미하므로 다음과 같이 기본 페이지를 로딩하는 등의 처리를 해 주면 되겠다.

[ views.py ]
def post_search(request):
    template_name = 'post_search.html'
    context = {}
    
    post_search_type = request.GET.get('post_search_type')
    post_search_keyword = request.GET.get('post_search_keyword')

    if not post_search_type or not post_search_keyword:
        ''' 기본 페이지를 로딩해주기 위한 logic'''

    else:
        ''' 키워드와 검색 방법을 가지고 해당하는 검색 결과를 출력해주기 위한 logic '''

    return render(request, template_name=template_name, context=context)

 

프로젝트 진행중 잠깐 막혀서 고생한 내용이라 기록을 해 둔다.



최근 글 목록