二级关联下拉菜单的增加与更新的实现
1.功能描述
通过按钮点击弹出对话框,实现添加信息或者更新信息,具体如下:
(1)新增界面

(2)更新编辑界面

2.新增实现过程概述
model层
class KuanDai(models.Model):
"""宽带基础信息表"""
accessnum = models.CharField(verbose_name="接入号",max_length=50,db_index=True)
mobilelable = models.CharField(verbose_name="移动标识",max_length=100)
customer = models.CharField(verbose_name="用户名称",max_length=50)
# city_choices = (
# (1, "沈阳"),
# (2, "大连"),
# (3, "鞍山"),
# (4, "抚顺"),
# (5, "本溪"),
# )
city = models.CharField(verbose_name="城市",max_length=50)
# area_choices = (
# (1, "和平"),
# (2, "铁西"),
# (3, "于洪"),
# (4, "皇姑"),
# (5, "大东"),
# )
area = models.CharField(verbose_name="区域",max_length=50)
address = models.CharField(verbose_name="具体地址",max_length=100)
desc = models.CharField(verbose_name="备注",max_length=200,null=True,blank=True,default="无")
其中city字段和area字段定义为Char型,但是由于前端不能让用户天马行空的数据,需要以元祖映射的形式接收数据,因为前段传过来的数据是数字

所以后端取到的对应字典的中的值就是数字,需要通过码表进行翻译

view层
def kuandai_add(request):
""" 新建订单(Ajax请求)"""
##浏览器通过POST方法送给后端的数据,利用KuanDaiModelForm类型传入并实例化,赋给form
form = KuanDaiModelForm(data=request.POST)
##数字校验
if form.is_valid():
# 构造一个post回传值与存入数据库值的字典
city_choices = (
(0, "沈阳市"),
(1, "大连市"),
(2, "鞍山市"),
(3, "抚顺市"),
(4, "本溪市"),
(5, "丹东市"),
(6, "锦州市"),
(7, "营口市"),
(8, "阜新市"),
(9, "辽阳市"),
(10, "盘锦市"),
(11, "铁岭市"),
(12, "朝阳市"),
(13, "葫芦岛市"),
)
# 借助上面的字段获取城市内容
form.instance.city = city_choices[int(request.POST.get("city"))][1]
# 获取区域内容
form.instance.area = request.POST.get("area")
# 获取地址内容
form.instance.address = request.POST.get("address")
# 保存到数据库中
form.save()
## 返回成功状态的字符串
return JsonResponse({"status": True})
## 校验失败则返回失败字符串及失败原因
return JsonResponse({"status": False, 'error': form.errors})
ModelForm层
采取了多继承的关系实现的 :定义KuanDaiModelForm继承BootStrapModelForm,BootStrapModelForm同时继承BootStrap和forms.ModelForm
KuanDaiModelForm:
from app01 import models
from app01.utils.bootstrap import BootStrapModelForm
class KuanDaiModelForm(BootStrapModelForm):
class Meta:
model = models.KuanDai
# fields = "__all__"
# fields = [""]
exclude = ["city","area"]
BootStrapModelForm:
from django import forms
class BootStrap:
bootstrap_exclude_fields = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for name, field in self.fields.items():
if name in self.bootstrap_exclude_fields:
continue
# 字段中有属性,保留原来的属性,没有属性,才增加。
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {
"class": "form-control",
"placeholder": field.label
}
class BootStrapModelForm(BootStrap, forms.ModelForm):
pass
class BootStrapForm(BootStrap, forms.Form):
pass
注意:
(1)KuanDaiModelForm中的exclude中的字段,表示不需要传入前端进行渲染
(2)BootStrap中的bootstrap_exclude_fields中的字段,表示传入前端,但不需要加载init中的样式
(3)上面两者的作用不同,不要混淆
模板层:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">新增宽带信息</h4>
</div>
<div class="modal-body">
<form id="formAdd">
<div class="clearfix">
<div class="col-xs-6">
<div class="form-group" style="position: relative;margin-bottom: 20px;">
<label>接入号</label>
<input type="text" name="accessnum" maxlength="50" class="form-control"
placeholder="接入号" required="" id="id_accessnum">
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
</div>
<div class="col-xs-6">
<div class="form-group" style="position: relative;margin-bottom: 20px;">
<label>移动标识</label>
<input type="text" name="mobilelable" maxlength="50" class="form-control"
placeholder="移动标识" required="" id="id_mobilelable">
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
</div>
<div class="col-xs-6">
<div class="form-group" style="position: relative;margin-bottom: 20px;">
<label>用户名</label>
<input type="text" name="customer" maxlength="50" class="form-control"
placeholder="用户名" required="" id="id_customer">
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
</div>
<div class="col-xs-6">
<div class="form-group" style="position: relative;margin-bottom: 20px;">
<label>备注</label>
<input type="text" name="desc" maxlength="50" class="form-control"
placeholder="备注" required="" id="id_desc">
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
</div>
<div class="col-xs-12">
<label for="">地市和区域</label>
</div>
<div class="btn-group col-xs-4 form-group" style="position: relative;margin-bottom: 20px;">
<select name="city" id="city" class="form-control form-group"
onchange="changeCity(this.value)">
<option value>--请选择地市--</option>
<option value="0">沈阳市</option>
<option value="1">大连市</option>
<option value="2">鞍山市</option>
<option value="3">抚顺市</option>
<option value="4">本溪市</option>
<option value="5">丹东市</option>
<option value="6">锦州市</option>
<option value="7">营口市</option>
<option value="8">阜新市</option>
<option value="9">辽阳市</option>
<option value="10">盘锦市</option>
<option value="11">铁岭市</option>
<option value="12">朝阳市</option>
<option value="13">葫芦岛市</option>
</select>
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
<div class="btn-group col-xs-4 form-group" style="position: relative;margin-bottom: 20px;">
<select name="area" id="area" class="form-control form-group">
<option value="0">--请选择区域--</option>
</select>
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
<div class="col-xs-12">
<div class="form-group" style="position: relative;margin-bottom: 20px;">
<label>详细地址</label>
<input type="text" name="address" maxlength="50" class="form-control"
placeholder="详细地址" required="" id="id_address">
<span class="error-msg" style="color: red;position: absolute;"></span>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button id="btnCancel" type="button" class="btn btn-default" data-dismiss="modal">取 消</button>
<button id="btnSave" type="button" class="btn btn-primary">保 存</button>
</div>
</div>
</div>
</div>
其中由于中间有两个标签要改写,不用text框而用select框,所以不能用for循环实现字段渲染,所以代码稍微长一些,其中”接入号“”移动标识””用户名“”备注“”详细地址“采用text标签,“地市”和“区域”采用select标签(自己重写),其中select框中的onchange属性,表示每次这个框的选定发生改变后,都会触发后面的函数changeCity(this.value)
从上面可知,一级标签采用手写的方式以select的方式呈现,此处要注意,页面展现的内容是汉字,但是每个标签对应的value是数字(0-13),为了与下面的二维数组对应
//1.创建一个二维数组用于存储
var cities = new Array();
cities[0] = new Array("和平区", "沈河区", "大东区", "皇姑区", "铁西区", "苏家屯区", "浑南区", "沈北新区", "于洪区", "辽中区", "新民市", "康平县", "法库县");
cities[1] = new Array("中山区", "西岗区", "沙河口区", "甘井子区", "旅顺口区", "金州区", "普兰店区", "瓦房店市", "庄河市", "长海县");
cities[2] = new Array("铁东区", "铁西区", "立山区", "千山区", "海城市", "金州区", "台安县", "岫岩满族自治县");
cities[3] = new Array("新抚区", "东洲区", "望花区", "顺城区", "抚顺县", "清原满族自治县", "新宾满族自治县");
cities[4] = new Array("平山区", "明山区", "溪湖区", "南芬区", "本溪满族自治县", "桓仁满族自治县");
cities[5] = new Array("元宝区", "振兴区", "振安区", "东港市", "凤城市", "宽甸满族自治县");
cities[6] = new Array("古塔区", "凌河区", "太和区", "凌海市", "北镇市", "义县", "黑山县");
cities[7] = new Array("站前区", "西市区", "老边区", "鲅鱼圈区", "盖州市", "大石桥市",);
cities[8] = new Array("海州区", "新邱区", "太平区", "细河区", "清河门区", "彰武县", "阜新蒙古族自治县");
cities[9] = new Array("白塔区", "文圣区", "宏伟区", "弓长岭区", "太子河区", "灯塔市", "辽阳县");
cities[10] = new Array("大洼区", "双台子区", "兴隆台区", "盘山县");
cities[11] = new Array("银州区", "清河区", "开原市", "调兵山市", "铁岭县", "西丰县", "昌图县");
cities[12] = new Array("双塔区", "龙城区", "北票市", "凌源市", "朝阳县", "建平县", "喀喇沁左翼蒙古族自治县");
cities[13] = new Array("连山区", "龙港区", "南票区", "兴城市", "绥中县", "建昌县");
function changeCity(val) {
//7.获取第二个下拉列表
var cityEle = document.getElementById("area");
//9.清空第二个下拉列表的option内容
cityEle.options.length = 0;
//2.遍历二维数组中的省份
for (var i = 0; i < cities.length; i++) {
if (val == i) { //注意!!比较的是角标
//3.遍历用户选择的省份下的城市
for (var j = 0; j < cities[i].length; j++) {
//alert(cities[i][j]);
//4.创建城市的文本节点
var textNode = document.createTextNode(cities[i][j]);
//5.创建option元素节点
var opEle = document.createElement("option");
//6.将城市的文本节点添加到option元素节点
opEle.appendChild(textNode);
//8.option元素节点添加到第二个下拉列表中去
cityEle.appendChild(opEle);
}
}
}
}
解释下上面代码的作用,先取到第二个下拉列表的定位(通过id,这里是“area”),对下拉列表清空。然后用一个循环对二维数组进行循环,判断if(val==i),其中这个val是函数传进来的参数,上面的changeCity(this.value),就是这个this.value,也就是select框中对应的value值,这个就是整个方法实现的精髓。
下面就是先抓到二维数组中对应的区域字段,然后用option进行拼接,再返回到下拉框中去
3.更新实现过程概述
其中model层,ModelForm层和模板层与新增功能一致,此处不再赘述
看view层和js功能代码
def kuandai_detail(request):
uid = request.GET.get("uid")
row_dict = models.KuanDai.objects.filter(id=uid).values("accessnum", 'mobilelable', 'customer', 'city', 'area',
'address', 'desc').first()
if not row_dict:
return JsonResponse({"status": False, 'error': "数据不存在。"})
list_area = city_area(row_dict['city'])
# 从数据库中获取到一个对象 row_object
result = {
"status": True,
"data": row_dict,
"area": list_area,
}
return JsonResponse(result)
function bindBtnEditEvent() {
$(".btn-edit").click(function () {
// 清空对话框中的数据
$("#formAdd")[0].reset();
// 抓取到uid参数
var uid = $(this).attr("uid");
EDIT_ID = uid;
// 发送Ajax去后端获取当前行的相关数据 /order/detail/?uid=123
$.ajax({
url: "/kuandai/detail/",
type: "get",
data: {
uid: uid
},
dataType: "JSON",
success: function (res) {
if (res.status) {
// 将数据赋值到对话框中的标签中。
$.each(res.data, function (name, value) {
$("#id_" + name).val(value);
})
// 写循环,循环你的city array,拿到每个city值和后端
let arrcity = ['沈阳市', '大连市', '鞍山市', '抚顺市', '本溪市', '丹东市', '锦州市', '营口市', '阜新市', '辽阳市', '盘锦市', '铁岭市', '朝阳市', '葫芦岛']
let city = ""
arrcity.forEach(function (value, index) {
if (value === res.data.city) {
city += `<option value="${index}" selected>${value}</option>`
// city += `<option value="${index + 1}" selected>${value}</option>`
} else {
city += `<option value="${index}">${value}</option>`
// city += `<option value="${index + 1}">${value}</option>`
}
})
$("#city").html(city)
// document.getElementById('city').innerHTML = s;
// 再写一个区域的循环抓取,找到去
let arrarea = res.area
let area = ""
arrarea.forEach(function (value, index) {
console.log(4444, value, index)
if (value === res.data.area) {
area += `<option value="${index + 1}" selected>${value}</option>`
} else {
area += `<option value="${index + 1}">${value}</option>`
}
})
$("#area").html(area)
// 修改对话框的标题
$("#myModalLabel").text("编辑宽带信息");
// 点击编辑,显示对话框
$('#myModal').modal('show');
} else {
alert(res.error);
}
}
})
});
}
(1)点击click后先将form框的信息清空
(2)uid是页面上带的,这个参数对我们很有用

(3)把上一步uid赋给全局变量,后续do操作可以利用
(4)利用ajax发送请求(把uid发送给后端)
(5)后端拿到uid后,去数据库中拿数据
(6)这个就到关键步骤了,需要自己构造个小码表和函数
city = (
(0, "沈阳市"),
(1, "大连市"),
(2, "鞍山市"),
(3, "抚顺市"),
(4, "本溪市"),
(5, "丹东市"),
(6, "锦州市"),
(7, "营口市"),
(8, "阜新市"),
(9, "辽阳市"),
(10, "盘锦市"),
(11, "铁岭市"),
(12, "朝阳市"),
(13, "葫芦岛市"),
)
area = (
["和平区", "沈河区", "大东区", "皇姑区", "铁西区", "苏家屯区", "浑南区", "沈北新区", "于洪区", "辽中区", "新民市", "康平县", "法库县"],
["中山区", "西岗区", "沙河口区", "甘井子区", "旅顺口区", "金州区", "普兰店区", "瓦房店市", "庄河市", "长海县"],
["铁东区", "铁西区", "立山区", "千山区", "海城市", "金州区", "台安县", "岫岩满族自治县"],
["新抚区", "东洲区", "望花区", "顺城区", "抚顺县", "清原满族自治县", "新宾满族自治县"],
["平山区", "明山区", "溪湖区", "南芬区", "本溪满族自治县", "桓仁满族自治县"],
["元宝区", "振兴区", "振安区", "东港市", "凤城市", "宽甸满族自治县"],
["古塔区", "凌河区", "太和区", "凌海市", "北镇市", "义县", "黑山县"],
["站前区", "西市区", "老边区", "鲅鱼圈区", "盖州市", "大石桥市"],
["海州区", "新邱区", "太平区", "细河区", "清河门区", "彰武县", "阜新蒙古族自治县"],
["白塔区", "文圣区", "宏伟区", "弓长岭区", "太子河区", "灯塔市", "辽阳县"],
["大洼区", "双台子区", "兴隆台区", "盘山县"],
["银州区", "清河区", "开原市", "调兵山市", "铁岭县", "西丰县", "昌图县"],
["双塔区", "龙城区", "北票市", "凌源市", "朝阳县", "建平县", "喀喇沁左翼蒙古族自治县"],
["连山区", "龙港区", "南票区", "兴城市", "绥中县", "建昌县"],
)
def city_area(cityid):
for item in city:
if cityid in item:
return area[item[0]]
上面函数的功能是,比如我传入参数”大连“,那么对应item[0]就等于1,进而area[item[0]]就会变成area[1],就把对应区域的列表值抓出来了,然后再返回。
view函数中的list_area赋给函数的返回值,然后打包返回给前端
success: function (res) {
if (res.status) {
// 将数据赋值到对话框中的标签中。
$.each(res.data, function (name, value) {
$("#id_" + name).val(value);
})
通过上面的代码,把后端传回来的值赋给对话框,其中利用("#id_" + name)这个定位到指定的text框,然后渲染

// 写循环,循环你的city array,拿到每个city值和后端
let arrcity = ['沈阳市', '大连市', '鞍山市', '抚顺市', '本溪市', '丹东市', '锦州市', '营口市', '阜新市', '辽阳市', '盘锦市', '铁岭市', '朝阳市', '葫芦岛']
let city = ""
arrcity.forEach(function (value, index) {
if (value === res.data.city) {
city += `<option value="${index}" selected>${value}</option>`
// city += `<option value="${index + 1}" selected>${value}</option>`
} else {
city += `<option value="${index}">${value}</option>`
// city += `<option value="${index + 1}">${value}</option>`
}
})
$("#city").html(city)
手工定义一级下拉菜单项,然后循环这个列表,判断value的值跟res.data.city相比,如果相等填入city且附加“selected”属性,如果不相等,就直接加入city,最后再把city返回给#city框
let arrarea = res.area
let area = ""
arrarea.forEach(function (value, index) {
if (value === res.data.area) {
area += `<option value="${index + 1}" selected>${value}</option>`
} else {
area += `<option value="${index + 1}">${value}</option>`
}
})
$("#area").html(area)
res.area送给前端然后循环,道理给上面一样

浙公网安备 33010602011771号