1

Forewarning: I'm very new to Django (and web development, in general).

I'm using Django to host a web-based UI that will take user input from a short survey, feed it through some analyses that I've developed in Python, and then present the visual output of these analyses in the UI.

My survey consists of 10 questions asking a user how much they agree with a a specific topic.

Example of UI for survey:

Example of UI input screen

For models.py, I have 2 fields: Question & Choice

class Question(models.Model):
    question_text = models.CharField(max_length=200)

    def __str__(self):
        return self.question_text

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

I am wanting to have a user select their response to all 10 questions, and then click submit to submit all responses at once, but I'm having trouble with how that would be handled in Django.

Here is the html form that I'm using, but this code snippet places a "submit" button after each question, and only allows for a single submission at a time.

NOTE: The code below is creating a question-specific form for each iteration.

{% for question in latest_question_list %}
    <form action="{% url 'polls:vote' question.id %}" method="post">
    {% csrf_token %}
        <div class="row">
            <div class="col-topic">
                <label>{{ question.question_text }}</label>
            </div>
            {% for choice in question.choice_set.all %}
                <div class="col-select">
                    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
                    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
                </div>
            {% endfor %}
        </div>

    <input type="submit" value="Vote" />
    </form>
{% endfor %}

I'm interested in how I would take multiple inputs (all for Question/Choice) in a single submission and return that back to views.py

EDIT: ADDING VIEWS.PY

Currently, my views.py script handles a single question/choice pair. Once I figure out how to allow users to submit the form one time for all 10 question/choices, I will need to reflect this in views.py. This could sort of be part 2 of the question. First, how do I enable a user to submit all of their responses to all 10 questions with one "submit" button? Second, how do I setup views.py to accept more than 1 value at a time?

views.py

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'polls/survey.html', {
            'error_message': "You didn't select a choice.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()

        return HttpResponseRedirect(reverse('polls:analysis'))

Please let me know if additional context it needed.

Thanks in advance!

-C

4
  • Could you tell us more about how you are currently fetching form data in your views.py? Commented Nov 24, 2017 at 9:03
  • @PiyushDas, Thank you for bringing this to attention. I've updated the description to include this information. Commented Nov 24, 2017 at 9:13
  • So, you are saying, on pressing submit, you are able to get just one question/choice pair, even though the user has responded to each one of the questions. Is that the issue? Commented Nov 24, 2017 at 9:22
  • I'm able to have the user submit each of their question responses one at a time, by creating an individual form for each of the 10 questions and having a "submit" button next to each of the 10 questions. What I'd like to do is allow the user to select all of their answers (one per question), and then click submit once to submit all 10 of their responses with a single submission. Commented Nov 24, 2017 at 9:51

3 Answers 3

2

Use getlist() In your views.py

if method=="POST":
    choices = request.POST.getlist('choice')

I feel you should change the input radio to checkbox. Radio won't allow multiple selection but Checkbox will. Refer here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.QueryDict.getlist

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the response. I may have been a bit unclear in my description, but in my case, there is only 1 response per question. I am wanting to have 10 questions & 10 responses submit in a single form submission. In the linked image in my description above, the question is the bold (i.e., "Abortion is a woman's unrestricted right"), and the response/choice is the radio button value.
1

Ideally, this should have been done with Django Forms. Django forms have widgets and RadioSelect is one of them. You can use that to render your form and get the answer to each question at once. But that will need a lot of change in the way you are currently doing things.

So, what you can do is, on click on a submit button, collect all the question/choice pairs and send them at once with a POST request.

{% for question in latest_question_list %}
    <form>
        <div class="row">
            <div class="col-topic">
                <label>{{ question.question_text }}</label>
            </div>
            {% for choice in question.choice_set.all %}
                <div class="col-select">
                    <input type="radio" name="choice" value="{{ choice.id }}" />
                    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
                </div>
            {% endfor %}
        </div>
    </form>
{% endfor %}
<input id="submit-btn" type="submit" value="Vote" />

<script>
    $(document).on('click', '#submit-btn', function(event){
        var response_data = []
        var question_objs = $('.col-topic');
        var choice_objs = $('.col-select');

        for(i=0;i<question_objs.length;i++){
            var question_text = $(question_objs[i]).find('label').text();
            var choice_id = $(choice_objs[i]).find('input').val();
            var choice_text = $(choice_objs[i]).find('label').text();
            var question_choice = {
                "question_text": question_text,
                "choice_id": choice_id,
                "choice_text": choice_text
            }
            response_data.push(question_choice);
        }
        $.ajax({
            type: "POST",
            url: "url_to_your_view",
            data: response_data,
            success: function(response){
                alert("Success");
            }
        });
    });
</script>

This is how your view should look like.

def question_choice_view(request):
    if request.method == "POST":
        question_choice_data = request.POST['data']
        # further logic

Now, question_choice_data is a list of dictionaries. Each dict in the list will have the question_text, choice_text and choice id of user's response.

1 Comment

Ah, I've never tried using Django Forms. I will try this out and get back to you. I appreciate the response. Will let you know if I am successful.
0

You just need to organize your template a bit differently in order to have multiple questions within the same form. Litteraly in HTML it would translate into multiple text inputs and then one submit input below, all within one single form:

<form action="{% url 'polls:vote' question.id %}" method="post">
    {% for question in latest_question_list %}
    {% csrf_token %}
        <div class="row">
            <div class="col-topic">
                <label>{{ question.question_text }}</label>
            </div>
            {% for choice in question.choice_set.all %}
                <div class="col-select">
                    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
                    <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
                </div>
            {% endfor %}
        </div>
    {% endfor %}
    <input type="submit" value="Vote" />
</form>

Is it working now ?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.