二级关联下拉菜单的增加与更新的实现

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">&times;</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送给前端然后循环,道理给上面一样

posted @ 2023-08-04 16:45  内秀的小光  阅读(169)  评论(0)    收藏  举报