Deseamos darte la mejor solución que encontramos en todo internet. Nosotros queremos que te sea de mucha ayuda y si puedes compartir alguna mejora siéntete libre de hacerlo..
Solución:
Con un poco de hackery, es bastante factible.
En el siguiente ejemplo, condado se utiliza en lugar de Estado y Municipio en lugar de Ciudad. Entonces, los modelos son los siguientes:
class County(models.Model):
name = models.CharField(_('Name'), max_length=100, unique=True)
class Municipality(models.Model):
county = models.ForeignKey(County, verbose_name=_('County'))
name = models.CharField(_('Name'), max_length=100)
class Location(models.Model):
name = models.CharField(max_length=100)
county = models.ForeignKey(County, verbose_name=_('County'))
municipality = models.ForeignKey(Municipality,
verbose_name=_("Municipality"))
Hay dos lados del problema: JavaScript del lado del cliente y representación de campo del lado del servidor.
El JavaScript del lado del cliente (con JQuery, se supone que se sirve desde /site_media/js/municipalidad.js) es como sigue:
var response_cache = ;
function fill_municipalities(county_id)
if (response_cache[county_id])
$("#id_municipality").html(response_cache[county_id]);
else
$.getJSON("/municipalities_for_county/", county_id: county_id,
function(ret, textStatus)
var options = '';
for (var i in ret)
options += '';
response_cache[county_id] = options;
$("#id_municipality").html(options);
);
$(document).ready(function()
$("#id_county").change(function() fill_municipalities($(this).val()); );
);
Ahora necesita la vista Ajax para servir a los municipios que pertenecen a un condado determinado (se supone que se sirve desde /municipalities_for_county/):
from django.http import JSONResponse
from django.utils.encoding import smart_unicode
from django.utils import simplejson
from myproject.places.models import Municipality
def municipalities_for_county(request):
if request.is_ajax() and request.GET and 'county_id' in request.GET:
objs = Municipality.objects.filter(county=request.GET['county_id'])
return JSONResponse(['id': o.id, 'name': smart_unicode(o)
for o in objs])
else:
return JSONResponse('error': 'Not Ajax or no GET')
Y finalmente el código del lado del servidor en administrador.py para representar el campo es el siguiente. Primero, las importaciones:
from django import forms
from django.forms import widgets
from django.forms.util import flatatt
from django.utils.encoding import smart_unicode
from django.utils.safestring import mark_safe
from django.contrib import admin
from django.utils.translation import ugettext_lazy
from myproject.places.models import Municipality, Location
Entonces, el widget:
class MunicipalityChoiceWidget(widgets.Select):
def render(self, name, value, attrs=None, choices=()):
self.choices = [(u"", u"---------")]
if value is None:
# if no municipality has been previously selected,
# render either an empty list or, if a county has
# been selected, render its municipalities
value = ''
model_obj = self.form_instance.instance
if model_obj and model_obj.county:
for m in model_obj.county.municipality_set.all():
self.choices.append((m.id, smart_unicode(m)))
else:
# if a municipality X has been selected,
# render only these municipalities, that belong
# to X's county
obj = Municipality.objects.get(id=value)
for m in Municipality.objects.filter(county=obj.county):
self.choices.append((m.id, smart_unicode(m)))
# copy-paste from widgets.Select.render
final_attrs = self.build_attrs(attrs, name=name)
output = [u'')
return mark_safe(u'n'.join(output))
A continuación, el formulario:
class LocationForm(forms.ModelForm):
municipality = forms.ModelChoiceField(Municipality.objects,
widget=MunicipalityChoiceWidget(),
label=ugettext_lazy("Municipality"), required=False)
class Meta:
model = Location
def __init__(self, *args, **kwargs):
"""
We need access to the county field in the municipality widget, so we
have to associate the form instance with the widget.
"""
super(LocationForm, self).__init__(*args, **kwargs)
self.fields['municipality'].widget.form_instance = self
Y finalmente, la clase de administrador:
class LocationAdmin(admin.ModelAdmin):
form = LocationForm
class Media:
js = ('http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js',
'/site_media/js/municipality.js')
admin.site.register(Location, LocationAdmin)
Avísame si algo no está claro.
Al final de todo puedes encontrar las ilustraciones de otros administradores, tú además puedes dejar el tuyo si te apetece.