Django y selects encadenados
Vera Mazhuga
Software Developer
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
Written by Vera Mazhuga
Vera specializes in writing and maintaining code for various applications. Her focus on problem-solving and efficient programming ensures reliable and effective software solutions.