Reputation: 53
I am practicing Django, and I have been stuck on this for a while now. I am trying to write a basic survey app. My issue is that when I submit my form, I can see that request.POST
contains the data I need, form.data
also contains it, but after I run form.is_valid()
, I am left with only the keys in the dict, no values.
class SurveyForm(forms.Form):
def __init__(self, *args, **kwargs):
questions = kwargs.pop('questions')
super(SurveyForm, self).__init__(*args, **kwargs)
for q in questions:
choices = []
for answer in q.choice_set.all():
choices.append((answer.pk, answer.choice_text))
self.fields[q.id] = forms.ChoiceField(label=q.question_text, required=False,
choices=choices, widget=forms.RadioSelect)
def answers(self):
for q, a in self.cleaned_data.items():
yield a
If I remove required=False
, I keep getting This field is required
although, I believe it's due to the validation, because it looks like the page refreshes when I hit submit, while if I actually leave the choices blank, it doesn't refresh and instead a small popup appears above the label.
Here is the view that uses it.
def step(request, survey_id, attempt_id, surveypage_nr):
survey = get_object_or_404(Survey, pk=survey_id)
attempt = get_object_or_404(Attempt, pk=attempt_id)
pages = survey.surveypage_set.all().order_by('page_nr')
page = pages.filter(page_nr=surveypage_nr).first();
questions = page.question_set.all()
form = SurveyForm(request.POST or None, questions=questions)
if form.is_valid():
for a in form.answers():
answer = get_object_or_404(Choice, pk=a)
attempt.score = attempt.score + answer.score
attempt.save()
return HttpResponseRedirect(reverse('results', args=(survey.id, attempt.id,)))
else:
context = {'page': page, 'form': form}
return render(request, 'survey/surveypage.html', context)
I tried checking the contents of the form after the is_valid()
call:
request.POST = {'3': '2', '4': '3', 'csrfmiddlewaretoken': 'f..m1'}
form.data = {'3': '2', '4': '3', 'csrfmiddlewaretoken': 'f..m1'}
form.cleaned_data = {3: '', 4: ''}. # Why are you cleaning my values, Django?
form.fields = OrderedDict([(3, <django.forms.fields.ChoiceField object at 0x106c2d5f8>),
(4, <django.forms.fields.ChoiceField object at 0x1055ebba8>)])
As you can see, request.POST
and form.data
contain exactly what I need, but after validation, form.cleaned_data
doesn't have values for the keys. Why is this happening? Help pls.
Upvotes: 0
Views: 371
Reputation: 599778
As the other answer pointed out, the key needs to be a string. Data in a POST is always a string, but your keys are currently int. So when Django goes to validate the data for field '3'
it finds nothing, so shows it as empty; meanwhile it doesn't have a field called 3
so throws away that key/value.
You should set your field IDs to strings:
self.fields[str(q.id)] = ...
Upvotes: 1