Django Form doesn't accept selection as valid choice. Can't see why

5.6k views Asked by At

i made a little form where I ask the user for some location (1st stage), then geocode the location and ask the user to confirm the location (2nd stage). Everything works fine, however, when I select a choice and try to submit the form to get to the 3rd stage, the form doesn't accept the selection and issues an error "Select a valid choice". Why?

I can't see where I made a mistake. Please let me know what i did wrong. Thank you!

my forms.py

from django.http import HttpResponseRedirect
from django.contrib.formtools.wizard import FormWizard
from django import forms
from django.forms.widgets import RadioSelect
from geoCode import getLocation

class reMapStart(forms.Form):
    location = forms.CharField()
    CHOICES = [(x, x) for x in ("cars", "bikes")]
    technology = forms.ChoiceField(choices=CHOICES)


class reMapLocationConfirmation(forms.Form):    
   CHOICES = []
   locations = forms.ChoiceField(widget=RadioSelect(), choices = [])

class reMapData(forms.Form):
    capacity = forms.IntegerField()

class reMapWizard(FormWizard):    
    def render_template(self, request, form, previous_fields, step, context=None):
        if step == 1:
            location = request.POST.get('0-location')
            address, lat, lng, country = getLocation(location)
            form.fields['locations'].choices = [(x, x) for x in address]
        return super(reMapWizard, self).render_template(request, form, previous_fields, step, context)

def done(self, request, form_list):
    # Send an email or save to the database, or whatever you want with
    # form parameters in form_list
    return HttpResponseRedirect('/contact/thanks/')

my urls.py

...
(r'^reMap/$', reMapWizard([reMapStart, reMapLocationConfirmation, reMapData])),
...

generated html code by Django for a random location after the 1st submission

<form action='.' method='POST'><div style='display:none'>
<input type='hidden' name='csrfmiddlewaretoken' value='0f61c17790aa7ecc782dbfe7438031a8' /></div>
<table>
    <input type="hidden" name="wizard_step" value="1" />
    <input type="hidden" name="0-location" value="market street san francisco" id="id_0-location" /><input type="hidden" name="0-technology" value="car" id="id_0-technology" /><input type="hidden" name="hash_0" value="8a654e29d73f2c2f6660b5beb182f0c8" />
    <tr><th><label for="id_1-locations_0">Locations:</label></th><td><ul class="errorlist"><li>Select a valid choice. Market St, San Francisco, CA, USA is not one of the available choices.</li></ul><ul>

<li><label for="id_1-locations_0"><input checked="checked" type="radio" id="id_1-locations_0" value="Market St, San Francisco, CA, USA" name="1-locations" /> Market St, San Francisco, CA, USA</label></li>
</ul></td></tr>
</table>
<p><input type="submit" value="Submit" /></p>
</form>
2

There are 2 answers

0
Hannes On

Solution after Yuji's help:

initializing the class with a CharField

class reMapLocationConfirmation(forms.Form):
   locations = forms.CharField()

and then later overwriting to a choicefield

class reMapWizard(FormWizard):

    def render_template(self, request, form, previous_fields, step, context=None):
        if step == 1:
            location = request.POST.get('0-location')
            address, lat, lng, country = getLocation(location)
            form.fields['locations'] = forms.ChoiceField(widget=RadioSelect(), choices = [])
            form.fields['locations'].choices = [(x, x) for x in address]
        return super(reMapWizard, self).render_template(request, form, previous_fields, step, context)
0
Yuji 'Tomita' Tomita On

Try setting the default choices to all of your locations or don't make it a ChoiceField but a CharField and set it as a ChoiceField only where you override the form.

locations = forms.ChoiceField(widget=RadioSelect(), choices = [..all..])

I'm guessing the choices don't persist across multiple POSTs and the wizard validates all forms at the end.

Even if your form is valid for that one step, it becomes invalid at the end.

So, add all locations to the original field constructor or make it a CharField to remove auto validation of choices.