Django管理员内联的国家/州/城市下拉菜单 [英] Country/State/City dropdown menus inside the Django admin inline

查看:184
本文介绍了Django管理员内联的国家/州/城市下拉菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个城市外键由BusinessBranch模型。我的城市模式还有州和县的国家和国家的外键。我很难在我的BusinessBranchInline中显示州和国家的下拉菜单。什么是实现这一目标的最佳方法?如果下拉列表根据其父级的值筛选项目将是巨大的。



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆