Django管理员内联的国家/州/城市下拉菜单 [英] Country/State/City dropdown menus inside the Django admin inline
问题描述
django admin截图http://i33.tinypic.com/15n69mq。 png
有点黑客,这是相当可行的。
在以下示例中,使用县而不是州和市政而不是城市。所以,模型如下:
class County(models.Model):
name = models.CharField _('Name'),max_length = 100,unique = True)
class Municipality(models.Model):
county = models.ForeignKey(县,verbose_name = _(' )
name = models.CharField(_('Name'),max_length = 100)
class位置(models.Model):
name = models.CharField(max_length = 100)
county = models.ForeignKey(县,verbose_name = _('县'))
municipality = models.ForeignKey(Municipality,
verbose_name = _(Municipality))
问题有两方面:客户端JavaScript和服务器端字段渲染。
客户端JavaScript(假定从 /site_media/js/municipality.js 提供的JQuery)如下所示:
var response_cache = {};
函数fill_municipalities(county_id){
if(response_cache [county_id]){
$(#id_municipality)。html(response_cache [county_id]);
} else {
$ .getJSON(/ citiesities_for_county /,{county_id:county_id},
函数(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] =选项;
$(#id_municipality)。html(options);
});
}
}
$(document).ready(function(){
$(#id_county)。change(function(){fill_municipalities (this).val());});
});
现在,您需要Ajax视图来服务属于给定县的市政当局(假定从
从django.http导入JSONResponse
from django.utils来自django.utils的输入smart_unicode
$ m
从myproject.places.models import Municipality
def cityities_for_county(request):
如果请求.is_ajax()和request.GET和'county_id'请求.GET:
objs = Municipality.objects.filter(county = request.GET ['county_id'])
返回JSONResponse([{' id':o.id,'name':smart_unicode(o)}
for objs])
else:
返回JSONResponse({'error':'不是Ajax或没有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。来自myproject.places.models import的城市,位置
然后,小部件:
class MunicipalityChoiceWidget(widgets.Select):
def render(self,name, value,attrs = None,choices =()):
self.choices = [(u,u---------)]
如果值为None:
#如果以前没有选择自治市,
#呈现一个空列表,或者如果一个县已经选择了
#,则将其市政当局
value =''
model_obj = self.form_instance.instance
i f model_obj和model_obj.county:
for model in model_obj.county.municipality_set.all():
self.choices.append((m.id,smart_unicode(m)))
else :
#如果某个市政府X被选中,
#只显示这些城市,属于
#到X的县
obj = Municipality.objects.get(id = value)
in Municipality.objects.filter(county = obj.county):
self.choices.append((m.id,smart_unicode(m)))
#复制粘贴从widgets.Select.render
final_attrs = self.build_attrs(attrs,name = name)
output = [u'< select%s>'%flatatt(final_attrs)]
options = self.render_options(choices,[value])
如果选项:
output.append(options)
output.append('< / select>')
return mark_safe(u'\\\
..join(output))
接下来,表单:
class LocationForm(forms.ModelForm):
municipality = forms.ModelChoiceField(Municipality.objects,
widget = MunicipalityChoiceWidget(),
label = ugettext_lazy(Municipality),required = False)
class Meta:
model =位置
def __init __(self,* args,** kwargs):
我们需要访问市政小部件的县域,所以我们
必须将窗体实例与窗口小部件相关联。
super(LocationForm,self).__ init __(* args,** kwargs)
self.fields ['municipality']。widget.form_instance = self
最后,管理类:
code> 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)
如果有什么不清楚,请告诉我。
I have a city foreign key in by BusinessBranch model. My City model also has a state and country foreign keys for State and County models. I'm having hard time displaying State and Country dropdown menus inside my BusinessBranchInline. What would be the best way to achieve this? It would be great if the dropdowns filter items based on the value of its parent.
django admin screenshot http://i33.tinypic.com/15n69mq.png
With a little hackery, it's quite doable.
In the following example, County is used instead of State and Municipality instead of City. So, the models are as follows:
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"))
There are two sides of the problem: client-side JavaScript and server side field rendering.
The client side JavaScript (with JQuery, assumed to be served from /site_media/js/municipality.js) is as follows:
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()); });
});
Now you need the Ajax view for serving municipalities that belong to a given county (assumed to be served from /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'})
And finally the server side code in admin.py for rendering the field is as follows. First, the imports:
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
Then, the 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'<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))
Next, the form:
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
And finally, the admin class:
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)
Let me know if something remains unclear.
这篇关于Django管理员内联的国家/州/城市下拉菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!