I want to take value of selected radio buttons in a single page. To explain this here is my code in models.py file
class Quiz(models.Model):
Description = models.CharField(max_length=200)
def __str__(self):
return str(self.Description)
class Question(models.Model):
Question_Text = models.CharField(max_length=500)
Option1 = models.CharField(max_length=100)
Option2 = models.CharField(max_length=100)
Option3 = models.CharField(max_length=100, blank=True)
Option4 = models.CharField(max_length=100, blank=True)
Answer = models.CharField(max_length=100)
QuizID = models.ForeignKey(Quiz, on_delete=models.CASCADE)
def __str__(self):
return str(self.Question_Text)
I want user to choose one option from "Option1, Option2, Option3, Option4" fields and I want to get value of the selected radio button.
Here's my try:
disp.html
<form action="" method="post">
{% csrf_token %}
{% for q in question %}
{{ q.Question_Text }} <br>
<input type="radio" id="question_{{ q.Option1 }}" name="{{ q.id }}" value="{{ q.Option1 }}">
<label for="question_{{ q.Option1 }}">{{ q.Option1 }}</label> <br>
<input type="radio" id="question_{{ q.Option2 }}" name="{{ q.id }}" value="{{ q.Option2 }}">
<label for="question_{{ q.Option2 }}">{{ q.Option2 }}</label> <br>
{% if q.Option3 %}
<input type="radio" id="question_{{ q.Option3 }}" name="{{ q.id }}" value="{{ q.Option3 }}">
<label for="question_{{ q.Option3 }}">{{ q.Option3 }}</label> <br>
{% endif %}
{% if q.Option4 %}
<input type="radio" id="question_{{ q.Option4 }}" name="{{ q.id }}" value="{{ q.Option4 }}">
<label for="question_{{ q.Option4 }}">{{ q.Option4 }}</label> <br>
{% endif %}
{% endfor %}
<br> <input type="submit" class="btn btn-primary" value="Submit">
</form>
Now I want to get value of the selected radio button. Since the number of records may vary and hence I cannot take value of the selected radio buttons manually like:
first = request.POST.get("11")
second = request.POST.get("18")
third = request.POST.get("19")
Here 11,18 and 19 are the value of id field of records in Question Model.
So I tried for loop to do this in the following way but I am getting "None" as value.
view.py
def disp(request):
quiz = get_object_or_404(Quiz, id = 4)
question = get_list_or_404(Question, QuizID = quiz)
if request.method == "POST":
for q in question:
response = request.POST.get("q.id")
print(response)
return render(request, 'quiz/disp.html', {'question' : question, 'quiz' : quiz})
Please help me in getting the value of the selected radio button or if there's another way to get the value of selected radio button, please suggest me
POST <QueryDict> contains only keys of type <str>. Which means that request.POST.get(18) will return None and request.POST.get('18') will return the value (assuming that the key exists in POST <QueryDict>).
if request.method == "POST":
for q in question:
# convert the q.id into str
response = request.POST.get(str(q.id))
print(response)
OR
you may loop through the POST data and check for valid keys. Since, POST data contains other data like csrfmiddlewaretoken.
Change the value of radio button name attribute into the form of question_{{ q.id }}.
<input type="radio" id="question_{{ q.Option1 }}" name="question_{{ q.id }}" value="{{ q.Option1 }}">
Loop through POST and check if the key contains question_
if request.method == "POST":
for k, v in request.POST.items():
if 'question_' in k:
# do something
In view.py, you are using "q.id" as a HTTP param name while I think you intended it to be 11, 18, 19 etc. Try this :-
if request.method == "POST":
for q in question:
response = request.POST.get(q.id)
print(response)
I would reconfigure the Question model to use Choices:
SOME = 'win'
OTHER = 'lin'
Answer_CHOICES = (
(SOME, 'Some Answer'),
(OTHER, 'Other Answer'),
)
class Question(models.Model):
....
Options = models.CharField(choices=Answer_CHOICES, max_length=100)
....
Check the Choices field and how you may use it. Also, check crispy forms which automatically handle the form input for you.
Related
In models.py, question field contains text and question_img filed contains image. Questions may be text or image. If question filed contains text, question_img field should be empty and if question_img filed contains image, question filed should be empty. So, how to render text question or image question based on condition? If question field is empty then it should render question_img from Database vice-versa.
models.py:
class Questions(models.Model):
paper = models.CharField(max_length=10, default='None')
qs_no = models.IntegerField(default=None)
question = models.TextField(max_length=500)
question_img = models.ImageField(null=True, blank=True)
option_a = models.CharField(max_length=100)
option_b = models.CharField(max_length=100)
option_c = models.CharField(max_length=100)
option_d = models.CharField(max_length=100)
ans = models.CharField(max_length=50)
forms.py:
class QuestionsForm(forms.ModelForm):
paper = forms.CharField(widget=forms.Select(choices = PAPER_CHOICES))
class Meta:
model=Questions
fields=[
'paper',
'qs_no',
'question',
'question_img',
'option_a',
'option_b',
'option_c',
'option_d',
'ans',
]
views.py:
def questions(request):
if not request.user.is_superuser:
return render(request, 'login.html')
else:
if request.method == 'POST':
form = QuestionsForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('questions')
else:
return HttpResponseRedirect('questions')
else:
form = QuestionsForm()
return render(request, 'questions.html', {'form':form})
def render_questions(request):
print(f'user in render_questions is {request.user.username}', flush=True)
if not request.user.is_authenticated:
return render(request, 'login.html')
else:
global exam_session
exam_session = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10))
print(f"session id in render ques is {exam_session}", flush=True)
questions = Questions.objects.all()
ques = []
qs_no = 1
for q in questions:
que = {}
que['qs_no'] = qs_no
qs_no = qs_no + 1
que['question'] = q.question
que['id'] = q.id
que['option_a'] = q.option_a
que['option_b'] = q.option_b
que['option_c'] = q.option_c
que['option_d'] = q.option_d
ques.append(que)
print(f"ques: {ques}", flush=True)
return render(request, 'report.html', {'ques': ques})
template.html:
<form id="myform" name="myform" action="answer" method="POST">
{% csrf_token %}
<div class="questionContainer">
{% for question in ques %}
<div class="questiondiv" data-questionId="{{ question.id }}">
<div class="bghead1">
<h5><strong>Question {{ question.qs_no }}.</strong></h5>
</div>
<div class="font mrl">
<h5><input type="hidden" class="form-check-input" name="question" value="{{ question.question }}">{{ question.question }}</h5>
</div>
<div class="radio pad">
<label><input type="radio" class="form-check-input" name="question{{question.qs_no}}" value="{{question.option_a}}"> A) {{ question.option_a }}</label>
</div>
<div class="radio pad">
<label><input type="radio" class="form-check-input" name="question{{question.qs_no}}" value="{{question.option_b}}"> B) {{ question.option_b }}</label>
</div>
<div class="radio pad">
<label><input type="radio" class="form-check-input" name="question{{question.qs_no}}" value="{{question.option_c}}"> C) {{ question.option_c }}</label>
</div>
<div class="radio pad">
<label><input type="radio" class="form-check-input" name="question{{question.qs_no}}" value="{{question.option_d}}"> D) {{ question.option_d }}</label>
</div>
</div>
{% endfor %}
</div>
</form>
Using template if/else is a straightforward approach.
{% if question.question %}
<div class="font mrl">
<h5><input type="hidden" class="form-check-input" name="question" value="{{ question.question }}">{{ question.question }}</h5>
</div>
{% else %}
<div class="font mrl">
<h5><img src="{{ question.image.url }}"></h5>
</div>
{% endif %}
I'm creating quiz application, where user answers multiple choice questions and gets score. I've created everything, except calculating score. For this I should get value from radio buttons which user selected and compare it with correct answer. The problem is that, I can't get this value. Here are my codes:
models.py:
class Question(models.Model):
question_text = models.CharField(_('Sualın mətni'), max_length=250)
option_a = models.CharField(max_length = 50)
option_b = models.CharField(max_length = 50)
option_c = models.CharField(max_length = 50)
option_d = models.CharField(max_length = 50)
answer = models.CharField(max_length = 50)
views.py:
def index(request):
questions = Question.objects.all()
context = {
'questions': questions,
}
return render(request, 'index.html', context)
html:
<div class="main-container">
{% for question in questions %}
<div class="question-box">
<div class="question-text">
<p>{{ question.question_text }}</p>
</div>
<div class="question-answers">
<input class="option" type="radio" name="{{ question.id }}" value="{{ question.option_a }}">
<label>{{ question.option_a }}</label>
<input class="option" type="radio" name="{{ question.id }}" value="{{ question.option_b }}">
<label>{{ question.option_b }}</label>
<input class="option" type="radio" name="{{ question.id }}" value="{{ question.option_c }}">
<label>{{ question.option_c }}</label>
<input class="option" type="radio" name="{{ question.id }}" value="{{ question.option_d }}">
<label>{{ question.option_d }}</label>
</div>
</div>
{% endfor %}
<input type="submit" value="End quiz">
</div>
question.option_a
question.option_b
question.option_c
question.option_d
These variables hold the values as True or False
I am building a survey tool and I'm wondering how would I continue with this or if my current solution is even the proper way to do it.
Admin of the page may add or remove questions from questionnaires, so if I have understood it, I can't use ModelForms to handle the form data?
A form may consist of 5 multichoice questions and 2 free text questions or any other amount of different types of questions so there isn't any fixed type of questionnaire
How do I then save the values of the form as I do not have a model to use?
Is this even possible to achieve without using a model for the form?
Thank you for any input in advance.
views.py
from django.shortcuts import render
from .models import Questionnaire, Question, Answer
def index(request):
all_questionnaires = Questionnaire.objects.all()
all_questions = Question.objects.all()
return render(request, 'questions/index.html', locals())
def questionnaire_detail(request, questionnaire_id):
questionnaire = Questionnaire.objects.get(id=questionnaire_id)
questions = Question.objects.filter(questionnaire=questionnaire)
return render(request, 'questions/questionnaire.html',
{'questionnaire': questionnaire, 'questions': questions})
def calculate(request):
if request.method == 'POST':
pass
models.py
from django.db import models
MC = 'MC'
CN = 'CN'
TX = 'TX'
CATEGORY = (
(MC, 'Multichoice'),
(CN, 'Choose N'),
(TX, 'Text'),
)
VALYK = '1'
VALKA = '2'
VALKO = '3'
VALNE = '4'
VALVI = '5'
MULTICHOICE = (
(VALYK, 'Least'),
(VALKA, 'Less than average'),
(VALKO, 'Average'),
(VALNE, 'More than average'),
(VALVI, 'Most'),
)
class Questionnaire(models.Model):
questionnaire_name = models.CharField(max_length=100,
verbose_name="Questionnaire",
null=False,
default=None,
blank=False)
def __str__(self):
return self.questionnaire_name
class Question(models.Model):
questionnaire = models.ManyToManyField(Questionnaire)
question_text = models.CharField(max_length=200,
verbose_name="Questionnaire name",
null=True,
default=None,
blank=True)
question_category = models.CharField(max_length=2,
verbose_name="Question category",
null=False,
choices=CATEGORY,
default=None,
blank=False)
def __str__(self):
return self.question_text
class Answer(models.Model):
question = models.ForeignKey(Question)
class MultiChoiceAnswer(Answer):
answer = models.IntegerField(choices=MULTICHOICE)
def __str__(self):
return self.answer
questionnaire.html
{% extends "questions/base.html" %}
{% block title_html %}
Questionnaire
{% endblock %}
{% block h1 %}
Questionnaire
{% endblock %}
{% block content %}
{% if questions|length > 0 %}
<form action="{% url "questions:calculate" %}" method="post">
{% csrf_token %}
{% for question in questions %}
{{ question.question_text }}<br>
{% if question.question_category == "MC" %}
<input type="radio" name="{{ question.id }}" value="1"> 1<br>
<input type="radio" name="{{ question.id }}" value="2"> 2<br>
<input type="radio" name="{{ question.id }}" value="3"> 3<br>
<input type="radio" name="{{ question.id }}" value="4"> 4<br>
<input type="radio" name="{{ question.id }}" value="5"> 5<br>
{% elif question.question_category == "CN" %}
<input type="checkbox" name="{{ question.id }}" value="a">a<br>
<input type="checkbox" name="{{ question.id }}" value="b">b<br>
{% elif question.question_category == "TX" %}
<textarea rows="4" cols="50" name="{{ question.id }}">Test</textarea><br>
{% endif %}
{% endfor %}
<input type="submit" value="Send" />
</form>
{% else %}
<span>No questions</span>
{% endif %}
{% endblock %}
This is the solution I ended up with. Edited it a bit to be more generic.
In the view there is checking if the form was loaded or submitted. If it was submitted, then check the validity of all of the forms. As there are multiple forms they are then made as formsets.
View
def answerpage(request, questionnaire_pk):
AnswerFormSet = formset_factory(AnswerForm, extra=0)
questions = Question.objects.filter(questionnaire=questionnaire_pk)
qname = Questionnaire.objects.get(id=questionnaire_pk)
if request.method == 'POST':
answer_formset = AnswerFormSet(request.POST)
if answer_formset.is_valid():
for answer_form in answer_formset:
if answer_form.is_valid():
instance = answer_form.save(commit=False)
instance.fieldValue = answer_form.cleaned_data.get('fieldValue')
instance.save()
return redirect('main:calcs')
else:
return redirect('main:home')
else:
quest_id = request.session.get('questionnaire_key', defaultValue)
question_data = [{'question': question,
'questionnaire_key': quest_id} for question in questions]
answer_formset = AnswerFormSet(initial=question_data)
combined = zip(questions, answer_formset)
context = {
'combined': combined,
'answer_formset': answer_formset,
'qname': qname,
}
return render(request, 'main/questionnaire.html', context)
The form is a modelform with the default widgets overwritten.
Form
class AnswerForm(forms.ModelForm):
class Meta:
model = QuestionAnswer
exclude = ['']
widgets = {
'field1': RadioSelect(choices=CHOICES, attrs={'required': 'True'}),
'field2': HiddenInput,
}
Webpage renders the values from the view in to a table. Management_form is needed to handle the formset values correctly.
Webpage
{% extends "main/base.html" %}
{% load static %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/survey.css' %}">
<h1>{{ qname.questionnaire_text }}</h1>
<h2>{{ qname.description }}</h2>
<form method="post">{% csrf_token %}
{{ answer_formset.management_form }}
<table>
{% for question, form in combined %}
<tr><td style="width:65%">{{ question }}{{ question.question_type }}</td><td style="width:35%">{{ form.business_id }}{{ form.question }}{{ form.questionnaire_key }}{{ form.answer_text }}</td></tr>
{% endfor %}
</table>
<div class="buttonHolder">
<input type="submit" value="Save" id="next_button"/>
</div>
</form>
{% endblock %}
I have a page with list of questions. Each of them has radio button form with "Yes", "Maybe", "No" kind of choices. This form's submits by making a choice.
http://prntscr.com/embo1m
I can't understand how to connect question id with it's form. How to get it in it's view with response?
models.py
class Answer(models.Model):
user = models.ForeignKey(User)
apartment = models.ForeignKey(Apartment)
question = models.ForeignKey(Question)
choice = models.IntegerField(default=2)
def __str__(self):
return str(self.choice)
views.py
def questions_list(request, apartment_pk):
context = {}
context['apartment'] = get_object_or_404(Apartment, pk=apartment_pk)
context['questions'] = get_list_or_404(Question)
context['answer_form'] = AnswerForm
context['username'] = auth.get_user(request).username
if request.method == 'POST':
form = AnswerForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
return render(request, 'main/questions.html', context)
forms.py
class AnswerForm(ModelForm):
choice = ChoiceField(label='', widget=RadioSelect, choices=ANSWERS)
question_id = CharField(widget=HiddenInput(), required=False)
class Meta:
model = Answer
fields = ('choice', 'question_id')
template
<h1>{{ apartment.title }}</h1>
{% for question in questions %}
<h3>{{ question.title }}</h3>
<form id="question_{{ question.id }}" name="question_{{ question.id }}" action="/apartments/{{ apartment.id }}/" method="post">
{% csrf_token %}
{% for radio in answer_form.choice %}
<label><input name="choice" type="radio" value="{{ radio.choice_value }}" onchange="question_{{ question.id }}.submit()">{{ radio.choice_label }}</label>
{% endfor %}
{{ answer_form.hidden_field }}
</form>
{% endfor %}
EDIT:
Tried to pass question id as <input type="hidden" name="q_id" value="{{ question.id }}">
<h1>{{ apartment.title }}</h1>
{% for question in questions %}
<h3>{{ question.title }}</h3>
<form id="question_{{ question.id }}" name="question_{{ question.id }}" action="/apartments/{{ apartment.id }}/" method="post">
{% csrf_token %}
<input type="hidden" name="q_id" value="{{ question.id }}">
{% for radio in answer_form.choice %}
<label><input name="choice" type="radio" value="{{ radio.choice_value }}" onchange="question_{{ question.id }}.submit()">{{ radio.choice_label }}</label>
{% endfor %}
</form>
{% endfor %}
And changed my form to
class AnswerForm(Form):
choice = ChoiceField(label='', widget=RadioSelect, choices=ANSWERS)
But there's no hidden input in form from response...
<tr><th></th><td><ul id="id_choice">
<li><label for="id_choice_0"><input id="id_choice_0" name="choice" type="radio" value="0" required /> Точно ні</label></li>
<li><label for="id_choice_1"><input id="id_choice_1" name="choice" type="radio" value="1" required /> Скоріше ні</label></li>
<li><label for="id_choice_2"><input checked="checked" id="id_choice_2" name="choice" type="radio" value="2" required /> Не можу відповісти</label></li>
<li><label for="id_choice_3"><input id="id_choice_3" name="choice" type="radio" value="3" required /> Скоріше так</label></li>
<li><label for="id_choice_4"><input id="id_choice_4" name="choice" type="radio" value="4" required /> Точно так</label></li>
</ul></td></tr>
Cleaned data {'choice': '2'}
Pass the question id as hidden value as shown below:
<input type="hidden" name="q_id" value="{{ question.id }}">
{% for radio in answer_form.choice %}
<label><input name="choice" type="radio" value="{{ radio.choice_value }}" onchange="question_{{ question.id }}.submit()">{{ radio.choice_label }}</label>
{% endfor %}
For my MCQ app, I created a view
def process_data(request):
question_set=Question.objects.all()
choice_list=[]
question_set
for k, v in request.POST.items():
if k.startswith('choice'):
choice_list.append(v)
i=0
score=0
print type(question_set)
for question in question_set:
if question.answer1==choice_list[i]:
#print question.answer1
i=i+1
score=score+1
return HttpResponse(score)
html page contains the form look like this.
{% extends 'quiz/base.html' %}
{% block content%}
<h1>You are at quiz page</h1>
<form action="{% url 'quiz:process_data' %}" method="post">
{% csrf_token %}
{% for question in question_set %}
<h3>{{question.question_no}}.{{question.question_text }}</h3>
<input type="radio" name="choice{{ question.question_no}}" value="{{ question.option1 }}">{{ question.option1 }}<br>
<input type="radio" name="choice{{ question.question_no}}" value="{{ question.option2 }}">{{ question.option2 }}<br>
<input type="radio" name="choice{{ question.question_no}}" value="{{ question.option3 }}">{{ question.option3 }}<br>
<input type="radio" name="choice{{ question.question_no}}" value="{{ question.option4 }}">{{ question.option4 }}<br>
<input type="radio" name="choice{{ question.question_no}}" value="{{ question.option5 }}">{{ question.option5 }}<br>
{% endfor %}
<input type="Submit" name="Submit">
</form>
{% endblock%}
and this is the model for Questions
class Question(models.Model):
question_no=models.IntegerField(default=0)
question_text=models.CharField(max_length=1000)
option1=models.CharField(max_length=100)
option2=models.CharField(max_length=100)
option3=models.CharField(max_length=100)
option4=models.CharField(max_length=100)
option5=models.CharField(max_length=100)
answer1=models.CharField(max_length=100)
def __str__(self):
return self.question_text
The problem is that the score is not getting correctly. So that I tested it with the print statement and realized that only first questions answer is getting. How can I get the score correctly? Thank you
The problem is with how you have handled this call request.POST.item. The call to item function returns an unordered dictionary. This is causing your second for-loop to match user inputs against wrong question. Below is a sample code of what I mean:
user_inputs = request.POST.items() # key: choice<question_no> and value: <user_choice>
for question in question_set:
user_choice = user_inputs.get('choice'+question.question_no)
if user_choice == question.answer1:
//count the score