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

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

问题描述

我在 BusinessBranch 模型中有一个城市外键.我的城市模型还有一个州和县模型的州和国家外键.我很难在 BusinessBranchInline 中显示州和国家/地区下拉菜单.实现这一目标的最佳方法是什么?如果下拉列表根据其父项的值过滤项目,那就太好了.

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.

推荐答案

稍微有点技巧,它是完全可行的.

With a little hackery, it's quite doable.

在以下示例中,使用 County 代替 StateMunicipality 代替 City.因此,模型如下:

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"))

问题有两个方面:客户端 JavaScript 和服务器端字段渲染.

There are two sides of the problem: client-side JavaScript and server side field rendering.

客户端 JavaScript(使用 JQuery,假设从 /site_media/js/municipality.js 提供)如下:

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()); });
});

现在您需要 Ajax 视图来为属于给定县的市政当局提供服务(假设从 /municipalities_for_county/ 提供服务):

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'})

最后,admin.py 中用于渲染字段的服务器端代码如下.一、进口:

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

然后,小部件:

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'
'.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

最后,管理类:

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天全站免登陆