Django Admin实现省市区三级联动的完整指南
本文详细介绍如何在Django Admin后台实现省市区三级联动功能。通过自定义ModelForm和Admin模板,结合前端JavaScript与后端API,实现创建时按省市区顺序动态加载数据,以及编辑时自动回显已选值。涵盖从Model定义、URL配置到前端脚本的完整代码示例,帮助开发者快速掌握动态表单交互技巧。
本文介绍如何通过自定义Django Admin的模板文件来实现省市区三级联动功能。核心需求是在创建新记录时,用户依次选择省份、城市、区/县,系统需根据当前选择动态显示对应的下级数据。
在修改已有记录时,系统需默认加载并显示该记录中已存在的省市区数据,确保编辑体验的一致性。


首先定义数据模型,包含姓名、省份、城市及区/县字段。
class Member(models.Model):
name = models.CharField(max_length=100, verbose_name='姓名')
province = models.CharField(max_length=100, null=True, blank=True, verbose_name='省份')
city = models.CharField(max_length=100, null=True, blank=True, verbose_name='城市')
district = models.CharField(max_length=100, null=True, blank=True, verbose_name='区/县')
class Meta:
verbose_name_plural = verbose_name = '人员'
def __str__(self):
return self.name
接着配置视图函数与URL路由,用于处理前端发起的Ajax请求并返回对应的JSON数据。
# views
LOCATION = {'吉林省': {'长春市': ['南关区', '朝阳区', '二道区', '绿园区']}}
def choose_province(request):
province = list(LOCATION.keys())
return JsonResponse(province, safe=False)
def choose_city(request):
province = request.GET.get('p')
cities = list(LOCATION[province].keys())
return JsonResponse(cities, safe=False)
def choose_district(request):
province = request.GET.get('p')
city = request.GET.get('c')
districts = LOCATION[province][city]
return JsonResponse(districts, safe=False)
# urls
from person.views import choose_province, choose_city, choose_district
urlpatterns = [
path('province/', choose_province),
path('city/', choose_city),
path('district/', choose_district),
path('admin/', admin.site.urls),
]
在Admin配置中,指定自定义的表单类,并将省市区字段以单选框形式展示。
class MemberForm(forms.ModelForm):
class Meta:
widgets = {
'province': forms.Select(),
'city': forms.Select(),
'district': forms.Select()
}
@admin.register(Member)
class MemberAdmin(admin.ModelAdmin):
form = MemberForm
fields = ('name', ('province', 'city', 'district'))
list_display = ('name', 'province', 'city', 'district')
change_form_template = 'area.html'
需要编写一个自定义的ModelForm,将省份、城市、区/县这三个字段渲染为Select下拉框组件。
为了实现联动效果,需要编写特定的前端模板文件来处理JavaScript逻辑。
找到Django源码中默认的change_form.html文件(位于django/contrib/admin/templates/admin/目录下),将其复制到当前应用的templates目录中,以便进行覆盖修改。
在自定义的Admin类中,通过设置change_form_template属性为'area.html',指定使用刚才复制并修改后的模板文件。
{% block admin_change_form_document_ready %}
<script type="text/javascript"
id="django-admin-form-add-constants"
src="{% static 'admin/js/change_form.js' %}"
{% if adminform and add %}
data-model-name="{{ opts.model_name }}"
{% endif %}>
</script>
<script type="text/javascript">
(function($) {
$('#id_city').change(function() {
let p_id = $('#id_province').val();
let c_id = $('#id_city').val();
$.get('/district/', {"p": p_id, "c": c_id }, function(a_info) {
var area_info = $('#id_district').empty().append('<option value>' + '---------' + '</option>');
$.each(a_info, function(i, area) {
area_info.append('<option value="' + area + '">' + area + '</option>')
});
{% if change %}
$("#id_district").find("option:contains({{ original.district }})").attr('selected', true);
{% endif %}
});
});
$('#id_province').change(function() {
let p_id = $('#id_province').val();
$.get('/city/', { 'p': p_id }, function(c_info) {
var city_info = $('#id_city').empty().append('<option value>' + '---------' + '</option>');
$.each(c_info, function(i, city) {
city_info.append('<option value="' + city + '">' + city + '</option>')
});
{% if change %}
$("#id_city").find("option:contains({{ original.city }})").attr('selected', true);
$("#id_city").trigger("change");
{% endif %}
});
});
$.get('/province/', function(p_info) {
var province_info = $('#id_province').empty().append('<option value>' + '---------' + '</option>');
$.each(p_info, function(i, province) {
province_info.append('<option value="' + province + '">' + province + '</option>')
});
{% if change %}
$("#id_province").find("option:contains({{ original.province }})").attr('selected', true);
$("#id_province").trigger("change");
{% endif %}
});
})(django.jQuery);
</script>
参考资源: https://www.jb51.net/article/142409.htm
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









