axiacore

Blog

Django y selects encadenados

Vera Mazhuga

Vera Mazhuga

Published

1 min read.


Vamos a ver un ejemplo de cómo escribir formularios con selects encadenados en Django.


Hay casos cuando necesitamos escribir dos selects que dependen uno del otro. Por ejemplo, tenemos un modelo de países y otro de ciudades:

class Country(models.Model):
    name = models.CharField(
        max_length=100,
        verbose_name=u'nombre',
    )
class City(models.Model):
    name = models.CharField(
        max_length=100,
        verbose_name=u'nombre',
    )
    country = models.ForeignKey(
        'place.Country',
        verbose_name=u'país',
    )


y otro modelo que está relacionado con ciudades:

class Department(models.Model):
    name = models.CharField(
        max_length=100,
        verbose_name=u'nombre',
    )
    city = models.ForeignKey(
        'place.City',
        verbose_name=u'ciudad',
    )


Queremos crear un formulario para la creación de departamento en el que nuestro usuario pueda elegir primero un país y luego, de la lista de las ciudades filtrada por el país elegida, la ciudad.


En éste caso podemos usar un plugin para jQuery que nos permite encadenar dos selects: 
http://www.appelsiini.net/projects/chained.

$(function() {
    $("#id_city").chained("#id_country");
});


Para asociar los datos, el plugin Chained Selects necesita agregar un atributo 
class para el select de las ciudades en la que se indica el id del país correspondiente:


<pre data-gclp-id="0" data-initialized="true" lang="html"><br/><select id="id_country" name="country"><br/> <option value="" selected="selected">---------</option><br/> <option value="1">Colombia</option><br/> <option value="2">Rusia</option><br/></select><br/><select id="id_city" name="city"><br/> <option value="" selected="selected">---------</option><br/> <option value="1" class="1">Bogotá</option><br/> <option value="2" class="2">Moscú</option><br/> <option value="3" class="2">San Petersburgo</option><br/> <option value="4" class="1">Valledupar</option><br/></select><br/></pre>


Aquí se puede encontrar la demostración en CodePan: http://codepen.io/anon/pen/EapNPo.


Para hacer esto debemos redefinir el método 
render_option para el campo de la ciudad en forms.py:

class CityChainedSelectWidget(forms.Select) def render_option(self, selected_choices, option_value, option_label):<br/> option_value = force_text(option_value)<br/> if option_value in selected_choices:<br/> selected_html = mark_safe(u' selected="selected"')<br/> if not self.allow_multiple_selected:<br/> # Only allow for a single selection.<br/> selected_choices.remove(option_value)<br/> else:<br/> selected_html = u''<br/> customer_reference = u''<br/> if option_value:<br/> customer_id = City.objects.get(id=option_value).customer.id<br/> customer_reference = u' class={0}'.format(customer_id)<br/> return format_html(u'<option value="{0}"{1}{2}>{3}</option>',<br/> option_value,<br/> selected_html,<br/> customer_reference,<br/> force_text(option_label))<br/>class DepartmentForm(PersonForm):<br/> country = forms.ModelChoiceField(<br/> label=u'País',<br/> queryset=Country.objects.all(),<br/> )<br/> class Meta:<br/> model = Department<br/> fields = (<br/> 'name',<br/> 'city',<br/> )<br/> widgets = {<br/> 'city': CityChainedSelectWidget(),<br/> }<br/></pre>


Lo que hicimos fue reescribir el widget predeterminado de Django para los campos de select e indicar que al renderizar cada opción (elemento 
option) para cada ciudad, hay que agregar un nuevo atributo HTML class y asignar el id del país relacionado.


La imagen tomada de https://www.flickr.com/photos/mikeporesky/5432225640

Get updates from our CEO every other week about axiacore:

Learn about how we think:

Ascii Art

Algunas personas nos han preguntado acerca del batman que utilizamos en nuestro código fuente en todos los proyectos que real...

Sara Martinez

Sara Martinez

Published Feb 27, 2015

AxiaCore tiene nueva cuenta en Instagram

Estamos felices de anunciar que AxiaCore tiene un nueva cuenta en Instagram. Esta iniciativa nace porque queremos compar...

Pablo Vallejo

Pablo Vallejo

Published Jan 23, 2015

sudo y fabric para administrar y desplegar como devop

Automatizar labores de servidor permite reaccionar con más precisión y velocidad en ambientes en los cuales un administrador ...

Igor Támara

Igor Támara

Published Jan 15, 2015

We build software solutions from idea to market.

Let's Talk