I am creating a multi-choice quiz app, I have created a view which shows the question and 4 option. I have given radio button to each option but is giving me this error:
MultiValueDictKeyError at /quiz/2/11/ 'choice'
views.py
def question_detail(request,question_id,quiz_id):
q = Quiz.objects.get(pk=quiz_id)
que = Question.objects.get(pk=question_id)
ans = que.answer_set.all()
selected_choice = que.answer_set.get(pk=request.POST['choice'])
if selected_choice is True:
come = que.rank
came = come + 1
later_question = q.question_set.get(rank=came)
return render(request,'app/question_detail.html',{'que':que , 'later_question':later_question, 'ans':ans})
else:
come = que.rank
later_question = q.question_set.get(rank=come)
return render(request, 'app/question_detail.html', {'que': que, 'later_question': later_question, 'ans': ans})
question_detail.html
<form action="{% 'app:detail' quiz_id=quiz.id question_id=que.id %}" method="post">
{% csrf_token %}
{% for choice in que.answer_set.all %}
<input type="radio" name="choice" id="choice{{forloop.counter}}" value="{{choice.id}}">
<label for="choice{{forloop.counter}}">{{choice.answer}}</label>
{% endfor %}
</form>
Okay like I said in my comment, you're most likely getting that error because the POST object will be empty during a normal GET request. So you should wrap everything that's meant to happen after a request in an IF block:
if request.method === 'POST':
selected_choice = que.answer_set.get(pk=request.POST['choice'])
# Every other post-submit task
You should always check for the POST method in your views if you're expecting form data. Others have answered this more in-depth before so I would just direct you there:
What does request.method == "POST" mean in Django?
Related
I'm quiet new to Django, and I've been struggling with the following:
I have a view that initially has set1=0(False) and set2=1(True). A user can swap this,so to set set1=1(True) and set2=0(False). The user can do this by pushing the 'Update' button. My problem is, that it does change in the backend, but the frontend/view/html is not updated. And I have no idea why..
I created a small example, which, if this works, I'll also get my Django case working..
I have the following:
views.py
So first this view is used, and the initial values for set1 and set2 are set:
class MainSettingsView(generic.TemplateView):
extra_context = {"main_page": "active"}
context_object_name = 'main'
template_name = 'index.html'
set1 = int(model.set1 == True)
set2 = int(model.set2 == True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
model = Setting12.objects.get(pk=1)
context['set1'] = int(model.set1 == True)
context['set2'] = int(model.set2 == True)
return context
And then, based on the chosen option in the radio buttons, it changes the model/db and therefore also the set1 and set2:
class UpdateButton(generic.TemplateView):
extra_context = {"main_page": "active"}
context_object_name = 'setting12'
template_name = 'index.html'
def post(self, request, queryset=None, *args, **kwargs):
if update_type == "set1":
model = Setting12.objects.get(pk=1)
model.set1 = True
model.set2 = False
return redirect(reverse("main"))
elif update_type == "set2":
model = Setting12.objects.get(pk=1)
model.set1 = False
model.set2 = True
return redirect(reverse("main"))
For context, this is what I use in the html:
index.html
<form class="card" action="{% url 'setting12' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<h3 class="card-title">Update Settings</h3>
<input type="radio" name="update_type" value="set1" {% if view.set1 %}checked {%endif%}> set1
{% if view.set1 is 1 %} ( Current setting ) {% else %} {% endif %}</input>
<input type="radio" name="update_type" value="set2" {% if view.set2 %}checked {%endif%}> Set2
{% if view.set2 is 1 %} ( Current setting ) {% else %} {% endif %}</input>
<button class="btn btn-primary" type="submit">Update</button>
</form>
I do see that the db is changed, set1 and set2 are changed in value when the button is pushed. But I also see is that when it goes from MainSettingsView > UpdateButton > MainSettingsView that the model is not re-read.. it doesn't go over the model again. So I do think that that is the problem of not getting a updated view. But I can't find a way to do it...
Can someone help me? It's taking me days so far :s
I finally got it =D!!
By removing the view. part in my index.html, and removing
set1 = int(model.set1 == True)
set2 = int(model.set2 == True) I removed the whole initial setting that I couldn't overwrite anymore. After that it totally worked :)
I have three forms in three tabs respectively in a template.
I fill in the first tab, submit, fill in the second form, submit, fill in the third form, submit.
Is there a way to keep the data in each form after saving? I need to show them all together.
No, when I save the second form I lose my data on the first form.
input.html: template
<form class="tab-pane fade in active" id="demographics" method="post" >
<input type="hidden" name="form_id" value="demographics">
{%crispy frm%}
</form>
<form class="tab-pane fade" id="diagnosis" method="post">
<input type="hidden" name="form_id" value="diagnosis">
{%crispy frm_d%}
</form>
<form class="tab-pane fade" id="a_b_sickle" method="post">
<input type="hidden" name="form_id" value="a_b_sickle">
{%crispy frm_a_b_s%}
</form>
views.py
def input(request):
context = RequestContext(request)
if request.method == 'POST':
submitted = request.POST.get('form_id', '')
print submitted
if submitted == 'demographics':
# Get the Form1 instance
my_demographics = DemographicForm(request.POST)
#my_diagnosis = DiagnosisForm()
if my_demographics.is_valid():
my_demographics_object= my_demographics.save()
my_diagnosis=DiagnosisForm({'patient': my_demographics_object.patient_id, 'diagnosis_option': 'b-thalassaemia syndromes'})
my_a_b_sickle=A_b_sickle_thalForm({'patient': my_demographics_object.patient_id})
else:
my_diagnosis=DiagnosisForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'diagnosis':
my_diagnosis = DiagnosisForm(request.POST)
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
if my_diagnosis.is_valid():
my_diagnosis_object=my_diagnosis.save()
my_a_b_sickle =A_b_sickle_thalForm({'patient': my_diagnosis_object.patient})
else:
my_demographics = DemographicForm()
my_a_b_sickle = A_b_sickle_thalForm()
elif submitted == 'a_b_sickle':
my_a_b_sickle = A_b_sickle_thalForm(request.POST)
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
if my_a_b_sickle.is_valid():
my_a_b_sickle.save()
else:
raise ValueError('No form specified !')
else:
my_demographics = DemographicForm()
my_diagnosis = DiagnosisForm()
my_a_b_sickle= A_b_sickle_thalForm()
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
Any ideas please?
You can either submit them using ajax or send them back filled in your context. If you can get the saved objects between request by any association they have you can try:
For the second way you can try something like this:
my_demographics = DemographicForm(my_demographic_object)
my_diagnosis = DiagnosisForm(my_diagnosis_object)
my_a_b_sickle= A_b_sickle_thalForm(my_a_b_sickle)
return render(request,'input.html', {'frm':my_demographics, 'frm_d': my_diagnosis, 'frm_a_b_s': my_a_b_sickle})
In fact, with that you can even make that work as an update form with a little extra using the 'instance' attribute of ModelForm.
This question already has answers here:
Django forms Reverse for '' with arguments '(7,)' and keyword arguments '{}' not found
(2 answers)
Closed 9 years ago.
I am receiving this error
Reverse for 'option' with arguments '('',)' and keyword arguments '{}' not found.
while I am rendering my option page. The option page is the last page in a 3 part workstream. The first 2 pages work fine. I am not sure why nothing is rendering. My code is below:
views.py
def drui_index(request):
disease_list = Disease.objects.all()
context = {'disease_list':disease_list, 'hide_breadcrumb': hide_breadcrumb}
return render(request, 'drui_index.html', context)
def drui(request, disease_id):
disease = get_object_or_404(Disease, pk=disease_id)
if request.method == "POST":
indicatorInlineFormSet = IndicatorFormSet(request.POST, request.FILES, instance=disease)
if indicatorInlineFormSet.is_valid():
indicatorInlineFormSet.save()
return HttpResponseRedirect(reverse('option', kwargs={'disease_id':disease_id}))
else:
indicatorInlineFormSet = IndicatorFormSet(instance=disease)
return render(request, 'drui.html', {'disease':disease, 'indicatorInlineFormSet': indicatorInlineFormSet})
def option(request, disease_id):
disease = get_object_or_404(Disease, pk=disease_id)
if request.method == "POST":
optionInlineFormSet = OptionFormSet(request.POST, request.FILES, instance=disease, prefix='option')
outcomeInlineFormSet = OutcomeFormSet(request.POST, request.FILES, instance=disease, prefix='outcome')
if optionInlineFormSet.is_valid() and outcomeInlineFormSet.is_valid:
optionInlineFormSet.save()
outcomeInlineFormSet.save()
return HttpResponseRedirect(reverse('splash', kwargs={'disease_id':disease_id}))
else:
optionInlineFormSet = OptionFormSet(instance=disease,prefix='option')
outcomeInlineFormSet = OutcomeFormSet(instance=disease,prefix='outcome')
return render(request, 'option.html', {'optionInlineFormSet': optionInlineFormSet, 'outcomeInlineFormSet': outcomeInlineFormSet})
urls.py
url(r'^drui_index/$', 'Physician_UI.views.drui_index', name='drui_index'),
url(r'^drui_index/(?P<disease_id>\d+)/$', 'Physician_UI.views.drui', name='drui'),
url(r'^drui_index/(?P<disease_id>\d+)/option/$', 'Physician_UI.views.option', name='option'),
HTML drui_index.html
{% load url from future %}
<form class="disease_form" action="{% url "drui_index" %}" method="post">{% csrf_token %}
HTML drui.html
{% load url from future %}
<form class="disease_form" action="{% url "drui" disease.id %}" method="post">{% csrf_token %}
HTML option.html
{% load url from future %}
<form class="option_form" action="{% url "option" disease.id %}" method="post">{% csrf_token %}
As I mentioned before, the first 2 pages (drui_index, and drui) work fine but option.html does not. I included most of the code just in case I'm passing information in the wrong way.
I am using django 1.4
You should pass disease object in context in your option view. You are not passing disease object in context and in template you are using disease.id hence the error.
return render(request, 'option.html',
{'optionInlineFormSet': optionInlineFormSet,
'outcomeInlineFormSet': outcomeInlineFormSet,
'disease': disease})
I use the length tag in my template to count the number of items in my drop down list. The length is well displayed the first time the form is rendered. When the form is submitted and when the length has changed, the value is not updated but the drop down list is updated! Why? :(
In forms.py:
lawsToValidate=forms.ModelChoiceField(queryset=LawsIdsModel.objects.filter(validated=0), empty_label="Select a law to validate", widget=forms.Select(attrs={'onchange': 'this.form.submit();'}))
In my template:
{{ form.lawsToValidate.field.choices|length }}
<form id="lawsIdsForm" action="{% url lawsValidation.views.lawsView %}" method="post">{% csrf_token %}
{{ form.non_field_errors }}
{{ form.lawsToValidate.field.choices|length }} laws to validate!
<div id="lawsToValidateChoice" class="fieldWrapper">
{{ form.lawsToValidate.errors }}
{{ form.lawsToValidate }}
</div>
</form>
In views.py:
def lawsView(request):
responseDic={}
state="display"
if request.method == 'POST':
lawToValidate=request.POST.getlist('lawsToValidate')[0]
#if a law is selected
if lawToValidate!="":
law=LawsIdsModel.objects.get(id=lawToValidate)
#saves the law
if 'lawsValidationSaveButton' in request.POST:
law.validated=True
form = LawsIdsForm(request.POST, instance=law)
if form.is_valid():
form.save()
del form
state="saved"
responseDic['success']="The law releveAnnee=" + str(law.releveAnnee) + ", releveMois=" + str(law.releveMois) + ", noOrdre=" + str(law.noOrdre) + " has been validated!"
else:
state="ongoing"
#displays the retrieved information of the law to validate (selection of a law in the drop down list)
if state!="saved":
#a law has been selected in the drop down list -> the related information are displayed
if state=="display":
form = LawsIdsForm(instance=law, initial={'lawsToValidate': lawToValidate, 'releveAnnee': law.releveAnnee, 'releveMois': law.releveMois, 'noOrdre': law.noOrdre})
#an error occured while validating the law -> display of these errors
elif state=="ongoing":
form = LawsIdsForm(request.POST, instance=law, initial={'lawsToValidate': lawToValidate, 'releveAnnee': law.releveAnnee, 'releveMois': law.releveMois, 'noOrdre': law.noOrdre})
responseDic['form']=form
responseDic['law']=law
#~ #if form has not been created yet -> unbound form
if 'form' not in locals():
responseDic['form'] = LawsIdsForm()
return render_to_response('lawsValidation/index.html', responseDic, context_instance=RequestContext(request))
Thank you in advance,
Romain
I think you've come across issue 18066. It's been closed as 'needs info', but it looks like a bug to me.
As a work around, try
{{ form.lawsToValidate.field.choices.queryset.all|length }}
Argh. Hey all, i have a muy simple django question:
And argh, i'm sorry, i've read and read, and I am sure this is covered somewhere super-obviously, but i haven't found it!
How do i edit/update a model using django? Like, the data values? Not the model fields?
Here is my code! (I'm using a home-brew version of stuff!)
Here is the urls:
url(r'^editStory/(?P<id>\d+)$',
StoryModelView.as_view(
context_object_name='form',
template_name ='stories/editStory.html',
success_template= 'stories/editStorySuccess.html'
),
{},
'editStory'
),
Here is the view:
def get(self,request,id=None):
form = self.getForm(request,id)
return self.renderValidations(form)
def getForm(self, request,id):
if id:
return self.getModelById(request,id)
return StoryForm()
def getModelById(self,request,id):
theStory = get_object_or_404(Story, pk=id)
if theStory.user != request.user:
raise HttpResponseForbidden()
return StoryForm(theStory)
def renderValidations(self,form):
if self.context_object_name:
contextName = self.context_object_name
else:
contextName = 'form'
if self.template_name:
return render_to_response(self.template_name,{contextName:form})
else :
return render_to_response('stories/addStory.html',{contextName:form})
def getPostForm(self,request,id):
if id:
theStory = self.idHelper(request,id)
return StoryForm(request.POST,theStory)
return StoryForm(request.POST)
def processForm(self,form,request):
theStory = form.save(commit=False)
theStory.user = request.user
return theStory
Here is the template code:
{% block content %}
<h3>Edit story</h3>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<input type="submit" value="Submit"/>
</form>
{% endblock %}
try as i might, i either:
get an error
get nothing
i get an error with the code as-displayed, caused by this line
{% for field in form %}
and with the error of:
Caught AttributeError while rendering: 'Story' object has no attribute 'get'
or i get nothing - no data at all - if i change my "getModelById" method to read:
def getModelById(self,request,id):
theStory = get_object_or_404(StoryForm, pk=id)
if theStory.user != request.user:
raise HttpResponseForbidden()
return theStory
StoryForm is one of those "ModelForm" things, and its model is "Story".
SO! The question:
how do i fix this code to make it work? What have i done wrong?
You don't show what your class is inheriting from, but it seems like you're just using a standard single object display view. Instead, you should use one of the editing mixins that are provided for this purpose.
Without knowing what your model looks like, are you looking for something along the lines of
s = Story.objects.get(some criteria)
s.user = <some user>
s.save()
?
Sorry, I find your question a little vague.
Upon rereading, one thing jumped out at me:
You can't do a query (get, filter, or any variation on these) on a model-- you have to do it on an object manager, like objects.
So, as above, in your case, Story.objects.get_object_or_404 should solve your error.