인프런 커뮤니티 질문&답변

Jam님의 프로필 이미지
Jam

작성한 질문수

<M.B.I.T> 테스트 페이지 만들기! with Django

다음 버튼 누르면 MultiValueDictKeyError at /result/ 페이지가 노출됩니다.

작성

·

233

0

안녕하세요 강사님,

템플릿 적용하기 강의를 따라하다가 중간에 막히는 부분이 있어서 질문 드립니다.

question-1 의 답을 선택하고 다음 버튼을 클릭했는데 하기와 같은 이미지가 노출되는 것을 확인했습니다.

이 부분은 어떤 수강생 분이 올리셔서, 답변 달아주신 것을 확인하며 admin 페이지에서 제가 잘못 넣은 부분이 있는지를 확인하며, 혹시 몰라서 다시 입력한 것들을 삭제하고 재입력했는데도 동일하게 발생을 합니다.

아래는 admin 페이지에서 입력한 질문 및 선택지들이며, 강사님과 동일한 질문지를 하지 않고 인터넷에 돌아다니는 것을 기반으로 작성했습니다. (10개 question에 각각 2개의 선택지로 총 20개 choices)

result view에서 문항수와 디저트 유형 로그를 출력을 했구요.

혹시 몰라서 강사님이 확인해보라는 곳도 스크린샷 첨부드립니다.

혹시 몰라서 코드를 첨부합니다. 강사님과 다른 부분이 있다면 강사님께서는 developer로 쓰신 것을 dessert 로 썼습니다.

form.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE-edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" >
    <title>디저트 찾기</title>
    <link rel = "stylesheet" type = "text/css" href="{% static 'css/reset.css' %}">
    <link rel = "stylesheet" type = "text/css" href="{% static 'css/form.css' %}">
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
    <section id="survey">
        <div class="wrapper">
            <form id="form" action="/result/" method="post">
                {% csrf_token %}
                {% for question in questions %}
                <div class="test">
                    <div class="question_container">
                        <h3 class="number">{{ question.number }}/{{ questions.count }}</h3>
                        <h3 class="question">{{ question.content }}</h3>
                    </div>  
                    <div class="answer">
                        {% for choice in question.choice_set.all %}
                        <div>
                            <input type="radio" 
                                   name="question-{{ question.number }}" 
                                   id="choice-{{ choice.pk }}" 
                                   value="{{ choice.dessert.pk }}"/>
                  <label for="choice-{{ choice.pk }}">{{ forloop.counter }}. {{ choice.content }}</label>
                        </div>  
                        {% endfor %}
                    </div>
                   {% if not forloop.first %}
                        <div class="btn_wrap btn_sort">
                        {% else %}
                        <div class="btn_wrap">
                        {% endif %}
                        {% if not forloop.first %}
                            <button class="prev_btn">이전</button>
                        {% endif %}
                        {% if not forloop.last %}
                            <button class="next_btn">다음</button>
                        {% else %}
                            <input type="submit" value="제출" class="submit_btn"/>
                        {% endif %}
                        </div>
                </div>
            {% endfor %}
            </form>
        </div>
    </section>    
    <script type="text/javascript" src="{% static 'js/form.js' %}"></script>
</body>
</html>

답변 기다리겠습니다.

답변 1

0

Hojun Lee님의 프로필 이미지
Hojun Lee
지식공유자

"제출" 버튼이 아니라 "다음" 버튼을 눌렀는데 result 페이지로 넘어갔다는 얘기는 "다음" 버튼의 submit 기능을 막지 못했다는 얘기입니다.

무슨 얘기인가 하면, <form> 태그 안에 있는 <button> 태그들은 기본적으로 submit 기능을 가집니다. 그래서 버튼을 눌렀을 때, submit 되기를 원치 않으면 preventDefault 함수를 사용해야합니다.

이는 form.js에 작성되어 있습니다.

$(function(){
    $('.next_btn').click(function(e){
        let divs = $(this).parent().prev().children();
        let present_top = $(this).parent().parent()[0].offsetTop;
        let inputs = divs.find('input:checked');
        if(inputs.length < 1) {
            alert('문항이 선택되지 않았습니다.');
            return false;
        }
        e.preventDefault();
        scrollDown(present_top);
    });

    $('.prev_btn').click(function(e){
        let present_top = $(this).parent().parent()[0].offsetTop;
        e.preventDefault();
        scrollUp(present_top);
    });

    $("#form").submit(function() {
        let radios = $('input[type=radio]:checked');
        if(radios.length < 10) {
            alert("문항이 선택되지 않았습니다.");
            return false;
        }
        return true;
    });

    $("html, body").animate({
        scrollTop: 0
    }, 500);
});

next_btn과 prev_btn이 click 됐을 때 콜백 함수를 보면 e.preventDefault() 가 그 역할을 수행합니다.

이 부분이 잘 작성되어 있는지 확인 하시고, 이미 잘 작성되어 있는데도 submit이 일어난다면 캐시를 비워주세요.

"캐시 비우기 및 강력 새로고침"은 F12로 개발자 도구를 연 상태에서 새로고침 버튼을 우클릭하면 보일 것 입니다.

Jam님의 프로필 이미지
Jam
질문자

확인을 해보니 그 건에 대해서는 구현이 되어 있었습니다.

PC와 아이폰XR의 경우에는 동일한 에러가 나오는데 아이폰11pro에서는 다음 페이지로 넘어가고 있네요.

이게 해상도 차이점이 있나요?

Hojun Lee님의 프로필 이미지
Hojun Lee
지식공유자

네, 해상도 차이가 있습니다.

해당 문제는 나중에 발견되어서 마지막 챕터인 트러블슈팅 챕터에서 다룹니다.

미리 한 번 확인해보시는 것이 좋으실 것 같아요.

Jam님의 프로필 이미지
Jam
질문자

트러블 슈팅 챕터에 있는 코드를 사용했는데도 동일하네요,

이걸 어떻게 해결해야 될까요?ㅠ

Hojun Lee님의 프로필 이미지
Hojun Lee
지식공유자

혹시 캐시는 비워져 있으실까요?

전에 사용했던 코드가 계속 로드되고 있는 것이 아닌지 확인 부탁드립니다.

Jam님의 프로필 이미지
Jam
질문자

네 캐시는 할때마다 지웠습니다.

심지어 크롬 시크릿창에서도 열어봤는데 동일합니다.

Jam님의 프로필 이미지
Jam
질문자

혹시 원격이나 소스코드를 드리면 해결이 가능할까요?

강의 중간에 끊겨서 사실상 진도를 나가도 의미가 없을듯 합니다.

Jam님의 프로필 이미지
Jam
질문자

도움이 필요하면 원격으로도 해준다고 동영상에서 봤었는데, 요청을 드리니 대답이 없으시네요.

Jam님의 프로필 이미지
Jam

작성한 질문수

질문하기