美文网首页django
CMDB,告别数据库的CURD(基于django)

CMDB,告别数据库的CURD(基于django)

作者: 两分与桥 | 来源:发表于2018-06-07 19:32 被阅读20次

    为什么要设计CMDB?
    目标是搭建自动化平台,包括装机,软件,平台,代码,基础是资产管理,
    运维平台, 首要目的是对资产管理,自动更新数据,记录变更记录

    相对于
    1.Excel表格,麻烦
    2.一套系统,自动更新数据,拿到资产变更记录

    CMDB 是运维自动化项目
    运维管理服务器,绝大多数运维人员都不会开发
    运维工作:采购服务器,采购器件

    运维自动化项目
    减少人工干预,降低人员成本
    - 资产管理
    - 操作管理

    CMDB -- 存储基础信息
    - 运维自动化基础
    - 资产管理,,对于资产信息,没必要实时更新,只需要隔一段时间再去取就行了

    电脑--装机--系统--软件(环境),CMDB 工具使得可以快速自动化完成

    多个系统部署

    公司里指定自动化运维时,先制定规则,
    规定,公司的服务器系统版本,内核,各个模版,

    主机名不能重复,
    主板的sn号,每个主机的主板sn号都是唯一的,
    --不过,如果主机开启虚拟机,
    --虚拟机的sn号跟主机是相同的,

    java等强类型语言是编译运行的,也就是整个运行之前先编译一遍,看看哪里有问题,一旦出现问题就会运行不起来。
    而python是弱类型语言,边解释边运行,程序出现问题只会在程序运行到那个部分时才报错,要不然不会报错。

    对于记录日志,日志路径最好写成可修改形式的,也就是配置文件内,
    日志不要和程序放在一起,因为日志文件会变得越来越大,之后迁移很麻烦

    采集资产
    --1.agent 形式
    --2.ssh 类方式
    --3.saltstack 方式

    cmdb.png

    agent 形式,特定:需要agent客户端

    import subprocess
    import requests
    # pip3 install requests
    
    # ################## 采集数据 ##################
    # result = subprocess.getoutput('ipconfig')
    # result正则处理获取想要数据
    
    # 整理资产信息
    # data_dict ={
    #     'nic': {},
    #     'disk':{},
    #     'mem':{}
    # }
    
    # ##################  发送数据 ##################
    # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
    # 这里只是简写,具体还要完善
    
    

    ssh 类方式,特点:慢

    # 基于paramiko模块, pip3 install paramiko
    import requests
    import paramiko
    
    # ################## 获取今日未采集主机名 ##################
    #result = requests.get('http://www.127.0.0.1:8000/assets.html')
    # result = ['c1.com','c2.com']
    
    
    # ################## 通过paramiko连接远程服务器,执行命令 ##################
    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='192.168.14.36', port=22, username='wupeiqi', password='123')
    
    # 执行命令
    # stdin, stdout, stderr = ssh.exec_command('df')
    
    # 获取命令结果
    # result = stdout.read()
    
    # 关闭连接
    # ssh.close()
    # print(result)
    
    # data_dict = {result}
    
    # ##################  发送数据 ##################
    # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
    
    

    saltstack 方式,很多都在用

    我在Centos 7 安装 saltstack 的过程中,发现 rpm 添加不了,可以换一种方式安装,
    参考:https://blog.csdn.net/wanglei_storage/article/details/50574621

    这里下面的只是供参考,,

    # 1. 安装saltstack
    #       rpm --import https://repo.saltstack.com/yum/redhat/6/x86_64/latest/SALTSTACK-GPG-KEY.pub
    #
    #
    """
            Master: yum install salt-master
           Master准备:
                a. 配置文件,监听本机IP
                    vim /etc/salt/master
                    interface: 本机IP地址
                b. 启动master
                    /etc/init.d/salt-master start
    
    
            Slave:  yum install salt-minion
            Slave准备:
                a. 配置文件,连接那个master
                    vim /etc/salt/minion
                    master: 远程master地址
                b. 启动slave
                    /etc/init.d/salt-minion start
    
    2. 创建关系
        查看
        Master:salt-key -L
            Accepted Keys:
            Denied Keys:
            Unaccepted Keys:
                c1.com
                c2.com
                c3.com
            Rejected Keys:
        接受
        Master:salt-key -a c1.com
            Accepted Keys:
                c1.com
                c2.com
            Denied Keys:
            Unaccepted Keys:
                c3.com
            Rejected Keys:
    
    
    3. 执行命令
        master:
            salt 'c1.com' cmd.run  'ifconfig'
    
        import salt.client
        local = salt.client.LocalClient()
        result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
    
    """
    # ################## 获取今日未采集主机名 ##################
    #result = requests.get('http://www.127.0.0.1:8000/assets.html')
    # result = ['c1.com','c2.com']
    
    
    # ################## 远程服务器执行命令 ##################
    # import subprocess
    # result = subprocess.getoutput("salt 'c1.com' cmd.run  'ifconfig'")
    #
    # import salt.client
    # local = salt.client.LocalClient()
    # result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
    
    
    # ##################  发送数据 ##################
    # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
    
    

    链接:https://pan.baidu.com/s/1EtOF1t_9sA3Ey6WWJjQNdQ 密码:snsc




    告别数据库的CURD

    也就是用这一套模版,就可以实现各种models的操作,对各个不同的models,可以很快的做出一个增删改查的页面出来

    CMDB总结:

    1. 三种采集资产方式
      --唯一标识
    2. API
      --API验证(tornado源码,加密cookie+时间限制+访问记录)
      --数据库表结构
    3. 后台管理
      --告别CURD,公共组件(前端+后端配置)

    运维自动化项目
    减少人工干预,降低人员成本
    -- 资产管理
    -- 操作管理

    CMDB
    - 运维自动化基础
    - 资产管理

    功能:
    ---- Agent或中控机
    ---- 字典套字典 =》 数据
    ---- 认证API
    -------------a. 时间超时
    -------------b. 访问记录
    -------------c. 加密后进行比较
    ====> Tornado:源码中来了 <====
    - API
    - 后台管理(10分钟完成CURD)
    - 对于数据库表数据进行增删改查
    ==》 组件:基本增删改查 《===

    通用的数据库增删改查的插件,只需要修改config配置列表 ,就可以实现对各种models的操作

    注意:在js文件中,我没有写添加和删除事件,添加可以另起一个html页面,需要自定制,删除只需要传递一个id到后台就行了,,,
    保存传递到django中的数据也需要修改一下,,,也就是PUT那里。。。。

    models.py 文件

    
    class Asset(models.Model):
        """
        资产信息表,所有资产公共信息(交换机,服务器,防火墙等)
        """
        device_type_choices = (
            (1, '服务器'),
            (2, '交换机'),
            (3, '防火墙'),
        )
        device_status_choices = (
            (1, '上架'),
            (2, '在线'),
            (3, '离线'),
            (4, '下架'),
        )
    
        device_type_id = models.IntegerField(choices=device_type_choices, default=1)
        device_status_id = models.IntegerField(choices=device_status_choices, default=1)
    
        cabinet_num = models.CharField('机柜号', max_length=30, null=True, blank=True)
        cabinet_order = models.CharField('机柜中序号', max_length=30, null=True, blank=True)
    
        idc = models.ForeignKey('IDC', verbose_name='IDC机房', null=True, blank=True,on_delete=models.CASCADE)
        business_unit = models.ForeignKey('BusinessUnit', verbose_name='属于的业务线', null=True, blank=True,on_delete=models.CASCADE)
    
        tag = models.ManyToManyField('Tag')
    
        latest_date = models.DateField(null=True)
        create_at = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = "资产表"
    
        def __str__(self):
            return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order)
    
    

    views.py 文件

    from django.shortcuts import render,HttpResponse
    from django.views import View
    import json
    
    class AssetView(View):
    
        def get(self,request,*args,**kwargs):
            # 数据库中获取数据
            return render(request,'asset.html')
    
    class AssetJsonView(View):
        def get(self,request,*args,**kwargs):
            # 数据库中获取数据
            table_config = [
                {
                    'q': None,
                    'title': "选项",
                    'display': True,  # content 中的值会赋给td标签
                    'text': {'content': "<input type='checkbox' />","kwargs": {}},
                    'attrs': {}
                },
                {
                    'q': 'id',
                    'title': 'ID',
                    'display': False,  # 不显示
                    'text':{},
                    'attrs': {}
                },
                {
                    'q': 'device_type_id', # 这个字段用于去数据库中取值
                    'title': '资产类型', # 显示的字段名
                    'display': True,    # 两个@ 表示去全局变量中取值,@@之后的字符串是全局变量名称
                    'text': {'content': "{n}", 'kwargs': {'n': "@@device_type_choices"}},
                    'attrs': {} # attrs 中的数据会称为td的属性
                },
                {
                    'q': 'device_status_id',
                    'title': '状态',
                    'display': True,
                    'text': {'content': "{n}", 'kwargs': {'n': "@@device_status_choices"}},
                    'attrs': {'name':'device_status_id','origin':"@device_status_id",'edit-enable': 'true', 'edit-type': 'select',"global-name": 'device_status_choices'}
                },
                {
                    'q': 'idc__id',
                    'title': 'IDC',
                    'display': False,
                    'text': {},
                    'attrs': {}
                },
                {
                    'q': 'idc__name',
                    'title': 'IDC',
                    'display': True, # 一个@ 代表从当前的一组数据中取值
                    'text': {'content': "{n}", 'kwargs': {'n': "@idc__name"}},
                    'attrs': {'name':'idc_id','origin':"@idc__id",'edit-enable': 'true', 'edit-type': 'select',"global-name": 'idc_choices'}
                },
                {
                    'q': 'cabinet_order',
                    'title': '机柜位置',
                    'display': True,
                    'text': {'content': "{n}",'kwargs': {'n': "@cabinet_order"}},
                    'attrs': {'name':'cabinet_order','origin':"@cabinet_order",'edit-enable': 'true', 'edit-type': 'input'}
                },
                {
                    'q': 'cabinet_num',
                    'title': '机柜号',
                    'display': True,
                    'text': {'content': "{n}", 'kwargs': {'n': "@cabinet_num"}},
                    'attrs': {},
                },
                {
                    'q': None,
                    'title': '操作',
                    'display': True,
                    'text': {'content': "<a href='/assetdetail-{m}.html'>{n}</a>", 'kwargs': {'n': '查看详细','m': '@id'}},
                    'attrs': {},
                }
            ]
    
            q_list = []
            for i in table_config:  # 去数据库中取值
                if not i['q']:
                    continue
                q_list.append(i['q'])
    
            from repository import models
            # 分页组件用户获取数据
            data_list = models.Asset.objects.all().values(*q_list)
            data_list = list(data_list)
    
            result = {
                'table_config':table_config,
                'data_list':data_list,
                'global_dict': {
                    'device_type_choices': models.Asset.device_type_choices,
                    'device_status_choices': models.Asset.device_status_choices,
                    'idc_choices': list(models.IDC.objects.values_list('id','name'))
                },
                # 分页组件生成页码信息
                'pager': """<li><a>1</a></li><li><a>2</a></li><li><a>3</a></li><li><a>4</a></li><li><a>5</a></li>"""
    
            }
            return HttpResponse(json.dumps(result))
    
        def put(self,request,*args,**kwargs):
            content = request.body
            v = json.loads(str(content,encoding='utf-8'))
            print(v)
            ret = {
                'status':True
            }
            return HttpResponse(json.dumps(ret))
    
    

    所定制的 js,全部都封装到里面了,而我们引用时只需要引入js文件,并传入url路径就行了,而所操作的表格就需要在view中修改了,
    文档中有很多要注意的点,留作以后参考

    nbList.js 文件

    
    (function () {
            var requestUrl = null;
            function bindChangePager() {
                $('#idPagination').on('click','a',function () {  // 为页码绑定点击事件
                    var num = $(this).text(); // 事件为获取页码中li标签的text,也就是1,2,3,4,5
                    init(num);   // 执行 init 发送ajax,并更新table
                })
            }
    
            function bindSave() {  // 绑定保存按钮
                $('#idSave').click(function () {
                    var postList = [];
                    //找到已经编辑过的tr,tr has-edit='true'
                    $('#table_tb').find('tr[has-edit="true"]').each(function () {
                        // $(this) => tr
                        var temp = {};
                        var id = $(this).attr('row-id');
                        temp['id'] = id;
                        // 找到编辑过的tr标签,查找其中修改的值,原值存放在origin中,修改的值放在new-val
                        $(this).children('[edit-enable="true"]').each(function () {
                            // $(this) = > td
                            var name = $(this).attr('name');
                            var origin = $(this).attr('origin');
                            var newVal = $(this).attr('new-val');
                            if (origin != newVal){  // 修改过的,才发送到服务器
                                temp[name] = newVal;
                            }
                        });
                        postList.push(temp);
                    });
    
                    $.ajax({
                        url:requestUrl,
                        type: 'PUT',
                        data: {'post_list': JSON.stringify(postList)}, //json 发送不了字典,得首先格式字符串
                        dataType: 'JSON',
                        success:function (arg) {
                            if(arg.status){
                                init(1);
                            }else{
                                alert(arg.error);
                            }
                        }
                    })
                })
            }
    
            function bindReverseAll() {  // 绑定反选按钮
                $('#idReverseAll').click(function () {
                    $('#table_tb').find(':checkbox').each(function () {
                        // $(this) => checkbox
                        if($('#idEditMode').hasClass('btn-warning')) { // 进入编辑模式的状态
                            if($(this).prop('checked')){  // 获取checkbox的状态
                                $(this).prop('checked',false);  // 设定checkbox 为不选中
                                trOutEditMode($(this).parent().parent()); // 必须传递tr标签过去
                            }else{
                                $(this).prop('checked',true);
                                trIntoEditMode($(this).parent().parent());
                            }
                        }else{  // 未进入编辑模式,就只有checkbox的反向选择了
                            if($(this).prop('checked')){
                                $(this).prop('checked',false);
                            }else{
                                $(this).prop('checked',true);
                            }
                        }
                    })
                })
            }
    
            function bindCancelAll() { // 绑定取消按钮
                $('#idCancelAll').click(function () {
                    $('#table_tb').find(':checked').each(function () { // 找到所有选中的checkbox
                        // $(this) => checkbox ,,,使之变为false
                        if($('#idEditMode').hasClass('btn-warning')){
                            $(this).prop('checked',false);
                            // 退出编辑模式
                            trOutEditMode($(this).parent().parent());
                        }else{
                            $(this).prop('checked',false);
                        }
                    });
                })
            }
    
            function bindCheckAll() {  // 绑定全选按钮
                $('#idCheckAll').click(function () {
                    $('#table_tb').find(':checkbox').each(function () {
                        // $(this)  = checkbox
                        if($('#idEditMode').hasClass('btn-warning')){
                            if($(this).prop('checked')){
                                // 当前行已经进入编辑模式了
                            }else{
                                // 进入编辑模式
                                var $currentTr = $(this).parent().parent();
                                trIntoEditMode($currentTr);
                                $(this).prop('checked',true);
                            }
                        }else{
                            $(this).prop('checked',true);
                        }
                    })
                })
            }
    
            function bindEditMode() {  // 绑定进入编辑模式按钮
                $('#idEditMode').click(function () {
                    var editing = $(this).hasClass('btn-warning');
                    if(editing){
                        // 退出编辑模式
                        $(this).removeClass('btn-warning');
                        $(this).text('进入编辑模式');
    
                        $('#table_tb').find(':checked').each(function () { //找到所有选中的checkbox进入编辑模式
                            var $currentTr = $(this).parent().parent();
                            trOutEditMode($currentTr);
                        })
    
                    }else{
                        // 进入编辑模式
                        $(this).addClass('btn-warning');
                        $(this).text('退出编辑模式');
                        $('#table_tb').find(':checked').each(function () {  //找到所有选中的checkbox退出编辑模式
                            var $currentTr = $(this).parent().parent();
                            trIntoEditMode($currentTr);
                        })
                    }
                })
            }
    
            function bindCheckbox() {  // 为每一个checkbox绑定事件,这里为了避免之后添加的checkbox没有点击事件
                // $('#table_tb').find(':checkbox').click(),,(这个程序没有添加之后的checkbox),采用事件委托的方式绑定事件
                $('#table_tb').on('click',':checkbox',function () {
    
                    if($('#idEditMode').hasClass('btn-warning')){  // 要一直检测是否进入了编辑模式
                        var ck = $(this).prop('checked');
                        var $currentTr = $(this).parent().parent();
                        if(ck){
                            // 进入编辑模式
                            trIntoEditMode($currentTr);
                        }else{
                            // 退出编辑模式
                            trOutEditMode($currentTr)
                        }
                    }
                })
            }
    
            function trIntoEditMode($tr) {  // $tr 是tr标签
                $tr.addClass('success');  // success 是颜色效果
                $tr.attr('has-edit','true'); // 设置编辑过的标志
                $tr.children().each(function () {
                    // $(this) => td
                    var editEnable = $(this).attr('edit-enable');
                    var editType = $(this).attr('edit-type');
                    if(editEnable=='true'){
                        if(editType == 'select'){  // select 标签,在views中必须要把choice传递过来
                            var globalName = $(this).attr('global-name'); //  "device_status_choices"
                            var origin = $(this).attr('origin'); // 1
                            // 生成select标签
                            var sel = document.createElement('select');
                            sel.className = "form-control";
                            $.each(window[globalName],function(k1,v1){
                                var op = document.createElement('option');
                                op.setAttribute('value',v1[0]);
                                op.innerHTML = v1[1];
                                $(sel).append(op);
                            });
                            $(sel).val(origin);  // 这样可以设定select的选定值****
    
                            $(this).html(sel);
    
                            // 下拉框
                            /*
                            *  <select>
                            *      <option value='1'>在线</option>
                            *      <option value='2'>下线</option>
                            *      <option value='3'>离线</option>
                            *  </select>
                            *
                            * */
                            //  在线
    
    
                        }else if(editType == 'input'){
                            // input文本框
                            // *******可以进入编辑模式*******
                            var innerText = $(this).text();
                            var tag = document.createElement('input');
                            tag.className = "form-control";
                            tag.value = innerText;
                            $(this).html(tag);
                        }
                    }
                })
            }
    
            function trOutEditMode($tr){  // 退出编辑模式
                $tr.removeClass('success');
                $tr.children().each(function () {
                    // $(this) => td
                    var editEnable = $(this).attr('edit-enable');
                    var editType = $(this).attr('edit-type');
                    if(editEnable=='true'){
                        if (editType == 'select'){
                            // 获取正在编辑的select对象
                            var $select = $(this).children().first();
                            // 获取选中的option的value
                            var newId = $select.val();
                            // 获取选中的option的文本内容
                            var newText = $select[0].selectedOptions[0].innerHTML;
                            // 在td中设置文本内容
                            $(this).html(newText);
                            $(this).attr('new-val',newId); // 设置属性中更新的值
    
                        }else if(editType == 'input') {
                            // *******可以退出编辑模式*******
                            var $input = $(this).children().first();
                            var inputValue = $input.val();
                            $(this).html(inputValue);
                            $(this).attr('new-val',inputValue);
                        }
    
                    }
                })
            }
    
            String.prototype.format = function (kwargs) {  // 自定制的string 的 format 方法
                // this ="laiying: {age} - {gender}";
                // kwargs =  {'age':18,'gender': '女'}
                var ret = this.replace(/\{(\w+)\}/g,function (km,m) {
                    return kwargs[m];
                });
                return ret;
            };
    
            function init(pager) {
                $.ajax({
                    url: requestUrl,
                    type: 'GET',
                    data: {'pager':pager},
                    dataType: 'JSON',
                    success:function (result) {
                        initGlobalData(result.global_dict);
                        initHeader(result.table_config);
                        initBody(result.table_config,result.data_list);
                        initPager(result.pager);
                    }
                })
    
            }
            function initPager(pager){
                $('#idPagination').html(pager);  // 添加中views 传递过来的页码,也就是那一堆li标签
            }
    
            function initHeader(table_config) {
                /*
                table_config = [
                    {
                        'q': 'id',
                        'title': 'ID',
                        'display':false
                    },
                    {
                        'q': 'name',
                        'title': '随便',
                        'display': true
                    }
                ]
                 */
    
                 /*
                <tr>
                    <th>ID</th>
                    <th>用户名</th>
                </tr>
                */
                var tr = document.createElement('tr');
                $.each(table_config,function (k,item) {
                    if(item.display){  // display 的值就是view中传递过来,确定是否展示
                        var th = document.createElement('th');
                        th.innerHTML = item.title;
                        $(tr).append(th);
                    }
    
                });
                $('#table_th').empty();  // 添加之前需要先清空之前的值
                $('#table_th').append(tr);
            }
    
            function initBody(table_config,data_list){  // 添加数据,用键值对的方式,list 列表有序
                $('#table_tb').empty();
                for(var i=0;i<data_list.length;i++){
                    var row = data_list[i];
                    // row = {'cabinet_num': '12B', 'cabinet_order': '1', 'id': 1},
                    var tr = document.createElement('tr');
                    tr.setAttribute('row-id',row['id']);
                    $.each(table_config,function (i,colConfig) {
                       if(colConfig.display){
                           var td = document.createElement('td');
                           /* 生成文本信息 */
                           var kwargs = {};
                           $.each(colConfig.text.kwargs,function (key,value) {
    
                               if(value.substring(0,2) == '@@'){  // 两个@ 代表去全局变量中取值
                                   var globalName = value.substring(2,value.length); // 全局变量的名称
                                   var currentId = row[colConfig.q]; // 获取的数据库中存储的数字类型值
                                   var t = getTextFromGlobalById(globalName,currentId);
                                   kwargs[key] = t;
                               }
                               else if (value[0] == '@'){ // 一个@ 代表从当前 的一组数据中取值
                                    kwargs[key] = row[value.substring(1,value.length)]; //cabinet_num
                               }else{
                                    kwargs[key] = value;
                               }
                           });
                           var temp = colConfig.text.content.format(kwargs);  // format 是自定制的string方法
                           td.innerHTML = temp;                               // 格式化字符串,
                                                 // 'content': "{n}", 'kwargs': {'n': "@@device_type_choices"}
                                                // 如同上面的字符串,用kwargs 中的 n 代替 {n}
    
    
                           /* 属性colConfig.attrs = {'edit-enable': 'true','edit-type': 'select'}  */
                            $.each(colConfig.attrs,function (kk,vv) {
                                if(vv[0] == '@'){ //还必须为td设置属性,标识
                                    td.setAttribute(kk,row[vv.substring(1,vv.length)]);
                                }else{
                                    td.setAttribute(kk,vv);
                                }
                            });
    
                           $(tr).append(td);
                       }
                    });
    
                    $('#table_tb').append(tr);
                }
            }
    
            function initGlobalData(global_dict) {
                $.each(global_dict,function (k,v) {
                    // k = "device_type_choices"
                    // v= [[0,'xx'],[1,'xxx']]
                    // device_type_choices = 123;
                    window[k] = v;  // k 是一个字符串,这里是定义为全局变量,需要加 window
                })                  // 全局变量用来存储select_choice,foreignkey choice
            }
    
            function getTextFromGlobalById(globalName,currentId) {  // 从全局变量中获取值
                // globalName = "device_type_choices"
                // currentId = 1
                var ret = null;
                $.each(window[globalName],function (k,item) {
                    if(item[0] == currentId){
                        ret = item[1];
                        return
                    }
                });
                return ret;
            }
    
    
            jQuery.extend({
                'NB': function (url) {
                    requestUrl = url;
                    init();
                    bindEditMode();
                    bindCheckbox();
                    bindCheckAll();
                    bindCancelAll();
                    bindReverseAll();
                    bindSave();
                    bindChangePager();
                },
                'changePager': function (num) {
                    init(num);
                    // 页码
                }
            })
    })();
    
    // 整个封装到js内部空间,不为外部展示
    
    

    使用时非常简便,

    template 模版文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css" />
        <style>
    
        </style>
    </head>
    <body>
    {#    <select id="i1">#}
    {#        <option>上阿海</option>#}
    {#        <option>北京</option>#}
    {#        <option>广州</option>#}
    {#    </select>#}
    
        <div style="width: 800px;margin: 0 auto;">
            <h1>资产列表</h1>
            <div class="btn-group" role="group" aria-label="...">
              <button id="idCheckAll" type="button" class="btn btn-default">全选</button>
              <button id="idReverseAll" type="button" class="btn btn-default">反选</button>
              <button id="idCancelAll" type="button" class="btn btn-default">取消</button>
              <button id="idEditMode" type="button" class="btn btn-default">进入编辑模式</button>
              <button type="button" class="btn btn-default">批量删除</button>
              <button id="idSave" type="button" class="btn btn-default">保存</button>
              <a id="idAdd" href="/web/asset-add.html" class="btn btn-default">添加</a>
    {#            添加按钮需要自定制#}
            </div>
            <table class="table table-bordered">
                <thead id="table_th"></thead>
                <tbody id="table_tb"></tbody>
            </table>  
            // 这里是页码
            <ul id="idPagination" class="pagination">
    
            </ul>
        </div>
    
        <script src="/static/js/jquery-3.1.1.js"></script>
        <script src="/static/js/nbList.js"></script>
    
        <script>
            $(function () {
                $.NB("/web/asset-json.html");  // 这样就行了
            });
        </script>
        
    </body>
    </html>
    
    

    最终的效果图:


    cmdb.png

    cmdb,就到这里结束了,,,,

    分享文件:
    cmdb--告别CURD
    链接:https://pan.baidu.com/s/1UHnJtC6xQAFWBk2QxQs9TQ 密码:hi3s
    cmdb--LNH
    链接:https://pan.baidu.com/s/1ZWOd2z4hadlEYjzvyjXk8Q 密码:tle2
    模版文件效果图:

    cmdb.png

    参看博客:http://www.cnblogs.com/wupeiqi/articles/6192986.html

    相关文章

      网友评论

        本文标题:CMDB,告别数据库的CURD(基于django)

        本文链接:https://www.haomeiwen.com/subject/edknsftx.html