ChoiceField dinámico en un formulario

2,012 views
Skip to first unread message

Jose Jiménez López

unread,
Aug 12, 2009, 6:51:35 PM8/12/09
to djan...@googlegroups.com
Hola,

en mi modelo tengo dos campos, localidad y provincia, que son claves foráneas a dichas tablas.

def MyModel(models.Model):
    ...
    province = models.ForeignKey('app.Province', verbose_name=u'Provincia')
    locality = models.ForeignKey('app.Locality', verbose_name=u'Localidad')
    ...


y en mi formulario, quiero que cuando se muestre, solo se rellenen las provincias, y que según la provincia que elija el usuario, se rellene el campo localidades.

def MyForm(forms.Form):
    ...
    locality = forms.ChoiceField(label=u'Localidad', choices=((0,u'Seleccione una provincia'),), required=False)
    ...

El que se rellene cuando se selecciona la provincia es facil, lo he hecho usando jQuery. El problema viene cuando intento salvar el formulario. Ya que el ChoiceField tiene como choices solo la opción 0, cuando intenta validarlo y tiene el id de una localidad, dice que no es una opción válida.

¿Alguien sabe como puedo hacer esto? He intentado hacer un método clean_locality() en el formulario, pero esto no sobreescribe la validación de ese campo, sino que se añade.

La verdad es que llevo bastante rato perdido buscando una solución y no doy con ninguna...

Gracias. Saludos.

--
Jose Jiménez López
jjimen...@gmail.com
www.josejimenez.net

Camilo Nova

unread,
Aug 12, 2009, 8:27:52 PM8/12/09
to djan...@googlegroups.com
Si no usas un ChoiceField, sino un CharField en el fomulario??

2009/8/12 Jose Jiménez López <jjimen...@gmail.com>



--
Camilo Hernando Nova
Software Engineer

Jose Jiménez López

unread,
Aug 13, 2009, 3:08:54 AM8/13/09
to djan...@googlegroups.com
Hola Camilo, gracias por responder.
No había pensado en usar un CharField como dices. Supongo que a un CharField le puedo meter un Select como widget no?

Esta tarde lo pruebo a ver que tal.

Saludos.

2009/8/13 Camilo Nova <camil...@gmail.com>

A Melé

unread,
Aug 13, 2009, 4:14:01 AM8/13/09
to Django-es
Jose,

Precisamente hace unos días publiqué un artículo sobre cómo cambiar la
queryset de un ModelChoiceField, pero también puedes hacer lo mismo
con un ChoiceField: http://django.es/blog/modificar-queryset-modelchoicefield-dinamicamente/

Échale un vistazo. Sobreescribe el método __init__ de tu formulario
para que acepte un parámetro "provincia" que por defecto sea None y si
está presente seleccione las localidades pertenecientes a la provincia
dada como choices para el campo locality. Cuando el usuario envíe el
formulario puedes seleccionar las localidades de la provincia que ha
seleccionado y a continuación pasarlo al objeto formulario en el
momento que se construye. De esta forma se validará si la localidad
dada está en la lista de localidades pertenecientes a la provincia
dada. Por ejemplo:

# ...
if request.POST:
province = Province.objects.get(id=request.POST['province'])
MiFormulario(data=request.DATA, provincia=province)

else:
MiFormulario()
# ...

Un saludo,

Antonio Melé
http://antoniomele.es


On 13 ago, 09:08, Jose Jiménez López <jjimenezlo...@gmail.com> wrote:
> Hola Camilo, gracias por responder.
> No había pensado en usar un CharField como dices. Supongo que a un CharField
> le puedo meter un Select como widget no?
>
> Esta tarde lo pruebo a ver que tal.
>
> Saludos.
>
> 2009/8/13 Camilo Nova <camilo.n...@gmail.com>
>
>
>
>
>
> > Si no usas un ChoiceField, sino un CharField en el fomulario??
>
> > 2009/8/12 Jose Jiménez López <jjimenezlo...@gmail.com>
>
> > Hola,
>
> >> en mi modelo tengo dos campos, localidad y provincia, que son claves
> >> foráneas a dichas tablas.
>
> >> def MyModel(models.Model):
> >>     ...
> >>     province = models.ForeignKey('app.Province',
> >> verbose_name=u'Provincia')
> >>     locality = models.ForeignKey('app.Locality',
> >> verbose_name=u'Localidad')
> >>     ...
>
> >> y en mi formulario, quiero que cuando se muestre, solo se rellenen las
> >> provincias, y que según la provincia que elija el usuario, se rellene el
> >> campo localidades.
>
> >> def MyForm(forms.Form):
> >>     ...
> >>     locality = forms.ChoiceField(label=u'Localidad',
> >> choices=((0,u'Seleccione una provincia'),), required=False)
> >>     ...
>
> >> El que se rellene cuando se selecciona la provincia es facil, lo he hecho
> >> usando jQuery. El problema viene cuando intento salvar el formulario. Ya que
> >> el *ChoiceField* tiene como *choices* solo la opción 0, cuando intenta
> >> validarlo y tiene el id de una localidad, dice que no es una opción válida.
>
> >> ¿Alguien sabe como puedo hacer esto? He intentado hacer un método *
> >> clean_locality()* en el formulario, pero esto no sobreescribe la
> >> validación de ese campo, sino que se añade.
>
> >> La verdad es que llevo bastante rato perdido buscando una solución y no
> >> doy con ninguna...
>
> >> Gracias. Saludos.
>
> >> --
> >> Jose Jiménez López
> >> jjimenezlo...@gmail.com
> >>www.josejimenez.net
>
> > --
> > Camilo Hernando Nova
> > Software Engineer
>
> --
> Jose Jiménez López
> jjimenezlo...@gmail.comwww.josejimenez.net

Jose Jiménez López

unread,
Aug 13, 2009, 4:34:38 AM8/13/09
to djan...@googlegroups.com
Hola Antonio,

gracias por responser, muy interesante tu artículo :)

Pero no sé si es exactamente lo que necesito... como tu lo describes, una vez que el usuario selecciona la provincia, debería enviar el formulario, y volver a cargarlo completo pero ahora con las localidades filtradas a solo esa provincia. ¿Lo he entendido bien?
Ese no es exactamente mi caso, mi formulario no se recarga, solamente le introduzco los valores al combo de las localidades cuando el usuario selecciona una provincia mediante Ajax, sin necesidad de recargar el formulario.

Saludos.

2009/8/13 A Melé <antoni...@gmail.com>

A Melé

unread,
Aug 13, 2009, 5:55:27 AM8/13/09
to Django-es
Jose,

No es que se vuelva a cargar el formulario de cara al usuario. El
formulario tienes que construirlo en cada request, bien quieras
mostrarlo al usuario o validar los datos recibidos. No hace falta que
devuelvas el formulario de nuevo con las localidades filtradas, lo
puedes guardar directamente y redirigir al usuario a otra página o lo
que quieras hacer. Pero necesitas construir el formulario con las
localidades filtradas para validar que la localidad seleccionada forma
parte de las localidades correspondientes a la provincia seleccionada
así como validar el resto de campos. Por ejemplo puedes construir el
formulario con los datos recibidos por request.POST y si es correcto
guardar los datos y redirigir al usuario a otra página. Todo esto es
independiente de cambiar las localidades que se puedan seleccionar
mediante AJAX. No se trata de volver a enseñar el formulario al
usuario, sino de validarlo. De todas formas también te vale para
mostrar el formulario al usuario, en caso de que haya errores, sólo
con las localidades correspondientes a la provincia seleccionada en
principio y que cambien si cambias de provincia (de nuevo mediante
AJAX).

Por ejemplo podrías validar el formulario tras construir la lista de
choices en función de la provincia seleccionada y si todo es correcto
guardarlo. Por eso pasas la provincia seleccionada como parámetro
cuando construyes el formulario: para generar la lista de choices de
localidades (ver mi artículo) en función de esa provincia y poder
validarlo correctamente:

# ...
if request.POST:
province = Province.objects.get(id=request.POST['province'])
mi_form = MiFormulario(data=request.POST, provincia=province)
if mi_form.is_valid():
mi_form.save() # en caso de que sea un ModelForm, si no
acceder a mi_form.cleaned_data
return HttpResponseRedirect('/formulario-guardado/')
else:
# ...

Un saludo,

Antonio Melé
http://antoniomele.es

On 13 ago, 10:34, Jose Jiménez López <jjimenezlo...@gmail.com> wrote:
> Hola Antonio,
>
> gracias por responser, muy interesante tu artículo :)
>
> Pero no sé si es exactamente lo que necesito... como tu lo describes, una
> vez que el usuario selecciona la provincia, debería enviar el formulario, y
> volver a cargarlo completo pero ahora con las localidades filtradas a solo
> esa provincia. ¿Lo he entendido bien?
> Ese no es exactamente mi caso, mi formulario no se recarga, solamente le
> introduzco los valores al combo de las localidades cuando el usuario
> selecciona una provincia mediante Ajax, sin necesidad de recargar el
> formulario.
>
> Saludos.
>
> 2009/8/13 A Melé <antonio.m...@gmail.com>
> jjimenezlo...@gmail.comwww.josejimenez.net

Jose Jiménez López

unread,
Aug 13, 2009, 6:05:19 AM8/13/09
to djan...@googlegroups.com
Ahora si lo he entendido bien, y si que me soluciona el problema.

Muchas gracias Antonio.
Saludos.

2009/8/13 A Melé <antoni...@gmail.com>

Reply all
Reply to author
Forward
0 new messages