我有一个按BusinessBranch模型输入的城市外键。我的城市模型还具有州和县模型的州和国家外键。我很难在BusinessBranchInline中显示州和国家/地区下拉菜单。实现这一目标的最佳方法是什么?如果下拉列表根据其父项的值过滤项目,那就太好了。
有了一点黑客,这是相当可行的。
在以下示例中,使用County代替State和Municipality代替City。因此,模型如下:
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"))
问题有两个方面:客户端JavaScript和服务器端字段呈现。
客户端JavaScript(使用JQuery,假定从/site_media/js/municipality.js提供)如下:
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 = '<option value="" selected="selected">---------</option>'; for (var i in ret) { options += '<option value="' + ret[i].id + '">' + ret[i].name + '</option>'; } response_cache[county_id] = options; $("#id_municipality").html(options); }); } } $(document).ready(function() { $("#id_county").change(function() { fill_municipalities($(this).val()); }); });
现在,您需要Ajax视图来服务属于给定县的市政当局(假定从/ 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'})
最后,admin.py中用于呈现该字段的服务器端代码如下。一,进口:
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
然后,小部件:
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'<select%s>' % flatatt(final_attrs)] options = self.render_options(choices, [value]) if options: output.append(options) output.append('</select>') return mark_safe(u'\n'.join(output))
接下来,形式:
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
最后是admin类:
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)
让我知道是否还有不清楚的地方。