本节内容主要实现CMDB基础数据管理功能的实现,文档中会介绍到datatables后端分页实现和过滤查询功能的实现。在Django实战1中已经自定义了 添加、修改等自定义类视图,本节中可以直接使用。

1、字典管理页面实现

首先来实现字段管理的基础管理页面,针对字典的一系列操作,都将在这个页面上完成。

1.1 字典管理视图实现

新建sandboxMP/apps/cmdb/views_code.py,写入如下内容:

from django.views.generic import TemplateViewfrom system.mixin import LoginRequiredMixin
from custom import BreadcrumbMixin
from .models import Codeclass CodeView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):template_name = 'cmdb/code.html'def get_context_data(self):self.kwargs['code_parent'] = Code.objects.filter(parent=None)return super().get_context_data(**self.kwargs)

在上面视图中,通过重写get_context_data方法来返回字典数据中所有父类为None的上下文,用来作为过滤查询时的选择项。

1.2 字典管理访问URL

打开,sandboxMP/apps/cmdb/urls.py,添加如下内容:

from . import views_codeurlpatterns = ['''原有内容省略'''path('portal/code/', views_code.CodeView.as_view(), name='portal-code'),
]

根据权限管理中URL定义规则,这里将字段管理功能URL放到portal分组中;在实战2第三节中已经说明,新的URL都需要添加到权限系统。

1.3 字典管理模板配置

修建模板文件:sandboxMP/templates/cmdb/code.html,内容如下:

{% extends "base-left.html" %}
{% load staticfiles %}{% block css %}<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}"><link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}"><link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}{% block content %}<!-- Main content --><section class="content"><div id="devlist"><div class="box box-primary" id="liebiao"><div class="box-header"><div class="btn-group pull-left"><button type="button" id="btnRefresh" class="btn btn-default"><i class="glyphicon glyphicon-repeat"></i>刷新</button></div><div class="btn-group pull-left">&nbsp</div><div class="btn-group pull-left"><button type="button" id="btnCreate" class="btn btn-default"><i class="glyphicon glyphicon-plus"></i>新增</button></div><div class="btn-group pull-left">&nbsp</div><div class="btn-group pull-left"><button type="button" id="btnDelete" class="btn btn-default"><i class="glyphicon glyphicon-trash"></i>删除</button></div><div class="pull-right"><form class="form-inline" id="queryForm"><div class="form-group searchArea margin-r-5 margin-top-5"><label>字典分类:</label><select class="form-control inputText select2" name="parent" id="parent"><option style='text-align:center' value="">---所有---</option>{% for code in code_parent %}<option value={{ code.key}}>{{ code.value }}</option>{% endfor %}</select></div></form></div></div><div class="box-body"><table id="dtbList" class="display" cellspacing="0" width="100%"><thead><tr valign="middle"><th><input type="checkbox" id="checkAll"></th><th>ID</th><th>KEY</th><th>VALUE</th><th>所属</th><th>操作</th></tr></thead><tbody></tbody></table><br> <br></div></div></div></section><!-- /.content -->{% endblock %}{% block javascripts %}<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>{% endblock %}

==按下CRTL + S 保存并上传项目文件==

1.4 权限管理配置

URL数据内容:

运行项目,登陆系统,访问菜单管理页【系统】→ 【权限管理】→ 【菜单管理】,按照上面URL内容,将数据添加到菜单管理中:

http://172.16.3.100:8000/system/rbac/menu/

访问角色管理页【系统】→ 【权限管理】→ 【角色管理】,选择【系统管理】后面第三个树形按钮配置权限信息,将新配置的URL授权给角色组:系统管理,选择好菜单后(全选)点【生成】按钮。

http://172.16.3.100:8000/system/rbac/role/

完成权限配置就可以在页面中访问【配置管理】→ 【平台设置】→ 【字典管理】。

每一个视图功能的访问都需要做对应的权限配置,在后面不再列出添加和授权步骤。

2 字典添加功能实现

2.1 字典添加Form配置

打开文件:sandboxMP/apps/cmdb/forms.py,写入如下内容:

from django import formsfrom .models import Codeclass CodeCreateForm(forms.ModelForm):class Meta:model = Codefields = '__all__'error_messages = {'key': {'required': 'key不能为空'},'value': {'required': 'value不能为空'}}def clean(self):cleaned_data = super(CodeCreateForm, self).clean()key = cleaned_data.get('key')value = cleaned_data.get('value')if Code.objects.filter(key=key).count():raise forms.ValidationError('key:{}已存在'.format(key))if Code.objects.filter(value=value).count():raise forms.ValidationError('value: {}已存在'.format(value))

通过CodeCreateForm可以对输入数据的有效性进行验证,同时避免内容重复。

CTRL + S 保存并上传。

2.2 字典添加视图实现

打开:sandboxMP/apps/cmdb/views_code.py,添加CodeCreateView视图:

from custom import SandboxCreateView
from .forms import CodeCreateFormclass CodeCreateView(SandboxCreateView):model = Codeform_class = CodeCreateFormtemplate_name_suffix = '_create'def get_context_data(self, **kwargs):kwargs['code_parent'] = Code.objects.filter(parent=None)return super().get_context_data(**kwargs)

字典添加视图,使用了在django实战1中创建的SandboxCreateView,重写get_context_data 返回所有父类code,用于创建时候的选择项。
SandboxCreateView类当初在定义的时候,只返回了执行结果result(True or False),前端根据result结果来提示执行成果或执行失败,这里想要返回form中自定义的错误提示信息,修改sandboxMP/apps/custom.py中SandboxEditViewMixin,内容如下:

import reclass SandboxEditViewMixin:def post(self, request, *args, **kwargs):res = dict(result=False)form = self.get_form()if form.is_valid():form.save()res['result'] = Trueelse:pattern = '<li>.*?<ul class=.*?><li>(.*?)</li>'form_errors = str(form.errors)errors = re.findall(pattern, form_errors)res['error'] = errors[0]return HttpResponse(json.dumps(res), content_type='application/json')

2.4 字典添加URL配置

打开:sandboxMP/apps/cmdb/urls.py,添加新的URL:

urlpatterns = ['''原有内容省略'''path('portal/code/create/', views_code.CodeCreateView.as_view(), name='portal-code-create'),
]

2.5 模板配置

新建模板文件:sandboxMP/templates/cmdb/code_crate.html,内容如下:

{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}"><!-- iCheck for checkboxes and radio inputs -->
{% endblock %}
{% block main %}<div class="box box-danger"><form class="form-horizontal" id="addForm" method="post">{% csrf_token %}<div class="box-body"><fieldset><legend><h4>新建字典</h4></legend><div class="form-group has-feedback"><label class="col-sm-2 control-label">KEY</label><div class="col-sm-3"><input class="form-control" name="key" type="text"/></div><label class="col-sm-2 control-label">VALUE</label><div class="col-sm-3"><input class="form-control" name="value" type="text" /></div></div><div class="form-group has-feedback"><label class="col-sm-2 control-label">父菜单</label><div class="col-sm-3"><select class="form-control select2" name="parent"><option value=""></option>{% for parent in code_all %}<option value={{ parent.id }}> {{ parent.value }} </option>{% endfor %}</select></div><label class="col-sm-2 control-label">描述信息</label><div class="col-sm-3"><input class="form-control" id="desc" name="desc" type="text" /></div></div></fieldset></div><div class="box-footer "><div class="row span7 text-center "><button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button><button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button></div></div></form></div>{% endblock %}{% block javascripts %}<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script><script type="text/javascript">$("#btnSave").click(function () {var data = $("#addForm").serialize();$.ajax({type: $("#addForm").attr('method'),url: "{% url 'cmdb:portal-code-create' %}",data: data,cache: false,success: function (msg) {if (msg.result) {layer.alert('数据保存成功!', {icon: 1}, function (index) {parent.layer.closeAll(); //关闭所有弹窗});} else {layer.alert(msg.error, {icon: 5});//$('errorMessage').html(msg.message)}return;}});});/*点取消刷新新页面*/$("#btnCancel").click(function () {window.location.reload();});$(function () {//Initialize Select2 Elements$(".select2").select2();});</script>{% endblock %}

注意:在{% block javascripts %}标签中的$("#btnSave")方法在执行成功后,提示信息中通过msg.error来返回form中的错误提示信息。
给字典管理页 添加按钮绑定添加事件,打开sandboxMP/templates/cmdb/code.html,在{% block javascripts %}中的菜单高亮代码段后面添加如下代码:

// 刷新数据$("#btnRefresh").click(function () {oDataTable.ajax.reload();});//新建字典$("#btnCreate").click(function () {layer.open({type: 2,title: '新增',shadeClose: false,maxmin: true,area: ['800px', '400px'],content: "{% url 'cmdb:portal-code-create' %}",end: function () {//关闭时做的事情oDataTable.ajax.reload();}});});

2.6 权限管理配置

请将下面URL数据添加到菜单管理,并授权给【系统管理】角色组:

菜单添加和角色授权过程不再单独写出来了,前面内容已经介绍够了。

配置完授权后就可以通过字典管理页面中的添加按钮来添加新的字典数据:

http://172.16.3.100:8000/cmdb/portal/code/

3 字典数据列表展示

在django实战1中,我们使用datatables通过ajax来获取并展示数据信息,数据分页是使用的datatables的前端分页,本节将介绍使用datatables的后端分页功能。

3.1 自定义数据列表类

创建一个带有分页和过滤查询的数据列表Mixin类,可用于所有基于datatables后端分页的数据,打开sandbox/apps/custom.py,添加如下内容:

from django.views.generic import View
from django.http import JsonResponse
from django.db.models.query import QuerySet
from django.core.exceptions import ImproperlyConfiguredclass SandboxMultipleObjectMixin:filters = {}fields = []queryset = Nonemodel = None# 用来获取queryset,下面内容参照了Django通用类视图的基本写法def get_queryset(self):if self.queryset is not None:queryset = self.querysetif isinstance(queryset, QuerySet):queryset = queryset.all()elif self.model is not None:queryset = self.model._default_manager.all()else:raise ImproperlyConfigured("%(cls)s is missing a QuerySet. Define ""%(cls)s.model, %(cls)s.queryset."% {'cls': self.__class__.__name__})return querysetdef get_datatables_paginator(self, request):# 从request中获取datatables需要服务端处理的数据信息,具体内容参照下面知识点介绍datatables = request.GETdraw = int(datatables.get('draw'))start = int(datatables.get('start'))length = int(datatables.get('length'))order_column = datatables.get('order[0][column]')order_dir = datatables.get('order[0][dir]')order_field = datatables.get('columns[{}][data]'.format(order_column))# 使用self.get_queryset方法来获取queryset数据queryset = self.get_queryset()# 根据datatables传递回来的排序信息进行排序(支持正向和反向排序)if order_dir == 'asc':queryset = queryset.order_by(order_field)else:queryset = queryset.order_by('-{0}'.format(order_field))# 统计所有数据条目record_total_count = queryset.count()# 获取过滤字段filters = self.get_filters()# 获取需要在datatables中展示的字段fields = self.get_fields()if filters:queryset = queryset.filter(**filters)if fields:queryset = queryset.values(*fields)# 过滤后的数据条目record_filter_count = queryset.count()# 对queryset进行切片操作,只返回当前需要展示的数据object_list = queryset[start:(start + length)]data = list(object_list)# 下面内容是datatables后端分页必须返回的数据,网上有些说明return {'draw': draw,'recordsTotal': record_total_count,'recordsFiltered': record_filter_count,'data': data,}def get_filters(self):return self.filtersdef get_fields(self):return self.fieldsclass SandboxListView(LoginRequiredMixin, SandboxMultipleObjectMixin, View):"""JsonResponse some json of objects, set by `self.model` or `self.queryset`."""def get(self, request):context = self.get_datatables_paginator(request)return JsonResponse(context)

知识点介绍(查看代码中注释部分):
1、datatables 后端分页的请求参数和返回参数详情可以查看下面内容:

http://www.datatables.club/manual/server-side.html

2、JsonResponse(context) 接受字典数据,实现了json.dumps()和 HttpResponse两个功能,对比下SandboxEditViewMixin。

3.2 字典列表视图实现

打开sandboxMP/apps/cmdb/views_code.py,添加CodeListView:

from custom import SandboxListViewclass CodeListView(SandboxListView):model = Codefields = ['id', 'key', 'value', 'parent__value']def get(self, request):if 'parent' in request.GET and request.GET['parent']:self.filters = dict(parent__key=request.GET['parent'])return super().get(request)

知识点介绍:
1、CodeListView继承了SandboxListView,通过fields指定需要在列表中展示的字段,其中parent是一个外键,通过parent__value实现多级的取值。
2、重写get方法,从request中获取parent(前端页面中传递的是parent的key)内容,将数据组合成字典赋值给filters,后端会根据filters内容进行数据的过滤。

3.3 字典列表URL

打开sandboxMP/apps/cmdb/urls.py,添加如下内容:

from . import views_codeurlpatterns = ['''原有内容省略'''path('portal/code/list/', views_code.CodeListView.as_view(), name='portal-code-list'),
]

3.4 模板配置

打开sandboxMP/templates/cmdb/code.html,在{% block javascripts %}下菜单高亮代码段后面添加datatables初始化配置和数据过滤刷新ajax请求的代码段:

// datatables 初始化配置var oDataTable = null;$(function () {oDataTable = initTable();function initTable() {var oTable = $('#dtbList').DataTable($.extend(true, {},DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,{ajax: {"url": "{% url 'cmdb:portal-code-list' %}","data": function (d) {d.parent = $("#parent").val();}},columns: [DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,{data: "id",width: "5%",},{data: "key",//width : "20%",},{data: "value",//width : "20%",},{data: "parent__value",//width : "20%",},{data: "id",width: "10%",bSortable: "false",render: function (data, type, row, meta) {var ret = "";var ret = "<button title='详情' onclick='doUpdate("+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";ret = ret + "<button title='删除' onclick='doDelete("+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";return ret;}}],}));return oTable;}});//select2$(function () {//Initialize Select2 Elements$(".select2").select2();});//过滤刷新接口获取新的数据$("#parent").change(function () {oDataTable.ajax.reload();});

打开sandboxMP/static/plugins/datatables/dataTables.const-1.js,修改下面注释部分内容,把DEFAULT_OPTION 改成 SERVER_SIDE_OPTION

var DATATABLES_CONSTANT = {  // datatables常量  DATA_TABLES : {  SERVER_SIDE_OPTION : { // 把DEFAULT_OPTION改成SERVER_SIDE_OPTIONoLanguage : {  sProcessing : "处理中...",  sLengthMenu : "每页 _MENU_ 项",//"显示 _MENU_ 项结果,",  sZeroRecords : "没有匹配结果",  sInfo : "显示第 _START_ 至 _END_ 项结果(共 _TOTAL_ 项)",'''原有内容省略'''

系统中启用了后端分页,所以在初始化datatables表格的时候,使用的是daTables.const-1.js,这个文件中配置了后端分页的一些基本配置,上面代码中注释部分修改的名称只是为了却分前端分页的配置内容,同时在code.html初始化datatables的时候调取的是SERVER_SIDE_OPTION。

CRTL + S 保存并上传。

3.5 权限管理配置

请将下面URL数据添加到菜单管理,并授权给【系统管理】角色组:

3.6 后端分页功能测试

到这里后端分页和过滤功能已经完整实现了,将下面的字典数据添加到系统,验证各个功能:

运行项目,访问系统字典管理页,通过新增按钮完成上面字典数据的添加工作:

http://172.16.3.100:8000/cmdb/portal/code/

CTRL + F5 刷新页面,在页面中可以看到数据已经自动完成分页,我们和可以设置每页显示的数据条目,可以切换分页获取不同数据,可以通过字典分类进行数据过滤,可以点击表格头部进行数据排序。

3.6 datatables后端分页参数梳理方法

在使用datatables后端分页功能后,很多人面对一堆参数和后端的代码处理逻辑时会有点懵,先浏览一遍上面给的后端分页参数网址,了解参数的基本用途,然后使用Chrome浏览器访问字典管理页面,按F12打开浏览器调试窗口,F5刷新页面,选择Chrome调试窗口中的 Network → ?draw=... → Headers 往下拖在后面可以看到datatables传递给后台的参数。

对照自定义的SandboxMultipleObjectMixin中get_datatables_paginator(self, request)方法中通过request中获取的datattables分页参数,理解参数的具体意义。
也可以切换分页后查看chrome调试敞口中最新访问的?draw=..Headers中start参数的变化。
选择每页显示数据条目,对比下chrome调试敞口中最新访问的?draw=..Headers中length参数的变化。
点击表格头部KEY进行排序,查看chrome调试敞口中最新访问的?draw=..Headers中order[0][column],order[0][dir],columns[2][data]内容,然后再去理解下get_datatables_paginator(self, request)方法中获取参数的内容。

datatables = request.GET
draw = int(datatables.get('draw'))
start = int(datatables.get('start'))
length = int(datatables.get('length'))
order_column = datatables.get('order[0][column]')
order_dir = datatables.get('order[0][dir]')
order_field = datatables.get('columns[{}][data]'.format(order_column))

一定要去做下操作,然后在对比下参数,和后端代码中实现,才能够加深理解。

4 字典更新功能实现

4.1 字典更新Form验证

打开文件:sandboxMP/apps/cmdb/forms.py,添加如下内容:

class CodeUpdateForm(CodeCreateForm):def clean(self):cleaned_data = self.cleaned_datakey = cleaned_data.get('key')value = cleaned_data.get('value')if self.instance:matching_code = Code.objects.exclude(pk=self.instance.pk)if matching_code.filter(key=key).exists():msg = 'key:{} 已经存在'.format(key)raise forms.ValidationError(msg)if matching_code.filter(value=value).exists():msg = 'value:{} 已经存在'.format(value)raise forms.ValidationError(msg)

在更新字典数据的时候,同样需要验证输入字段的有效性,这点在CodeCreateForm中已经时间了,避免代码重复,这里直接继承CodeCreateForm。同时重写clean方法,排除当前修改的数据之外保证数据没有重复。

4.2 字典更新视图

字典更新视图可以使用SandboxUpdateView来实现,打开sandboxMP/apps/cmdb/views_code.py,添加CodeUpdateView:

from custom import SandboxUpdateView
from .forms import CodeUpdateFormclass CodeUpdateView(SandboxUpdateView):model = Codeform_class = CodeUpdateFormtemplate_name_suffix = '_update'def get_context_data(self, **kwargs):kwargs['code_parent'] = Code.objects.filter(parent=None)return super().get_context_data(**kwargs)

4.3 字典更新URL

打开sandboxMP/apps/cmdb/urls.py,添加新的url:

urlpatterns = ['''原有内容省略'''path('portal/code/update/', views_code.CodeUpdateView.as_view(), name='portal-code-update'),

4.4 模板配置

新建模板sandboxMP/templates/cmdb/code_update.html:

{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}"><!-- iCheck for checkboxes and radio inputs -->
{% endblock %}
{% block main %}<div class="box box-danger"><form class="form-horizontal" id="addForm" method="post"><input type="hidden" name='id' type='text' value="{{ code.id }}"/>{% csrf_token %}<div class="box-body"><fieldset><legend><h4>修改字典</h4></legend><div class="form-group has-feedback"><label class="col-sm-2 control-label">KEY</label><div class="col-sm-3"><input class="form-control" name="key" type="text" value="{{ code.key }}"/></div><label class="col-sm-2 control-label">VALUE</label><div class="col-sm-3"><input class="form-control" name="value" type="text" value="{{ code.value }}"/></div></div><div class="form-group has-feedback"><label class="col-sm-2 control-label">父菜单</label><div class="col-sm-3"><select class="form-control select2" name="parent"><option value={{ code.parent.id }}> {{ code.parent.value }} </option><option value=""></option>{% for parent in code_parent %}<option value={{ parent.id }}> {{ parent.value }} </option>{% endfor %}</select></div><label class="col-sm-2 control-label">描述信息</label><div class="col-sm-3"><input class="form-control" id="desc" name="desc" type="text" value="{{ code.desc }}"/></div></div></fieldset></div><div class="box-footer "><div class="row span7 text-center "><button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button><button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button></div></div></form></div>{% endblock %}{% block javascripts %}<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script><script type="text/javascript">$("#btnSave").click(function () {var data = $("#addForm").serialize();$.ajax({type: $("#addForm").attr('method'),url: "{% url 'cmdb:portal-code-update' %}",data: data,cache: false,success: function (msg) {if (msg.result) {layer.alert('数据保存成功!', {icon: 1}, function (index) {parent.layer.closeAll(); //关闭所有弹窗});} else {layer.alert(msg.error, {icon: 5});//$('errorMessage').html(msg.message)}return;}});});/*点取消刷新新页面*/$("#btnCancel").click(function () {window.location.reload();});$(function () {//Initialize Select2 Elements$(".select2").select2();});</script>{% endblock %}

打开sandboxMP/templates/cmdb/code.html,给修改绑定事件,在{% block javascripts %}中新建字典$("#btnCreate")的代码段后面添加如下内容:

//修改字典
function doUpdate(id) {layer.open({type: 2,title: '编辑',shadeClose: false,maxmin: true,area: ['800px', '400px'],content: ["{% url 'cmdb:portal-code-update' %}" + '?id=' + id, 'no'],end: function () {oDataTable.ajax.reload();}});
}

CTRL + S 保存并上传。

4.5 权限管理配置

请将下面URL数据添加到菜单管理,并授权给【系统管理】角色组:

运行项目测试字典修改功能。

5 字典删除功能实现

5.1 字典删除视图

回顾下用户管理、组织组织架构管理、菜单管理、角色管理这些功能中的删除视图的实现,尽管删除视图的实现在代码上已经算得上是很精简了,但是这些删除视图代码基本一致,所以也可以抽象出来写成自定义类。
打开sandboxMP/apps/custom.py,添加如下内容:

class SandboxDeleteView(LoginRequiredMixin, SandboxMultipleObjectMixin, View):def post(self, request):context = dict(result=False)queryset = self.get_queryset()if 'id' in request.POST and request.POST['id']:id_list = map(int, request.POST['id'].split(','))queryset.filter(id__in=id_list).delete()context['result'] = Trueelse:raise AttributeError("Sandbox delete view %s must be called with id. "% self.__class__.__name__)return JsonResponse(context)

打开sandboxMP/apps/cmdb/views_code.py,添加删除视图:

from custom import SandboxDeleteViewclass CodeDeleteView(SandboxDeleteView):model = Code

5.2 字典删除URL

打开sandboxMP/apps/cmdb/urls.py,添加新的URL:

urlpatterns = ['''原有内容省略'''path('portal/code/delete/', views_code.CodeDeleteView.as_view(), name='portal-code-delete'),]

5.3 模板配置

给删除按钮绑定删除事件,打开sandboxMP/templates/cmdb/code.html,在{% block javascripts %}标签中修改字典doUpdate()代码段后面添加如下内容:

//checkbox全选$("#checkAll").on("click", function () {if ($(this).prop("checked") === true) {$("input[name='checkList']").prop("checked", $(this).prop("checked"));$('#example tbody tr').addClass('selected');} else {$("input[name='checkList']").prop("checked", false);$('#example tbody tr').removeClass('selected');}});//批量删除$("#btnDelete").click(function () {if ($("input[name='checkList']:checked").length == 0) {layer.msg("请选择要删除的记录");return;}var arrId = new Array();$("input[name='checkList']:checked").each(function () {//alert($(this).val());arrId.push($(this).val());});sId = arrId.join(',');layer.alert('确定删除吗?', {title: '提示', icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸, time: 0 //不自动关闭, btn: ['YES', 'NO'], yes: function (index) {layer.close(index);$.ajax({type: "POST",url: "{% url 'cmdb:portal-code-delete' %}",data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},cache: false,success: function (msg) {if (msg.result) {layer.alert("操作成功", {icon: 1});oDataTable.ajax.reload();} else {//alert(msg.message);layer.alert("操作失败", {icon: 2});}return;}});}});});//删除单个数据function doDelete(id) {layer.alert('确定删除吗?', {title: '提示', icon: 3 //0:感叹号 1:对号 2:差号 3:问号 4:小锁 5:哭脸 6:笑脸, time: 0 //不自动关闭, btn: ['YES', 'NO'], yes: function (index) {layer.close(index);$.ajax({type: "POST",url: "{% url 'cmdb:portal-code-delete' %}",data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},cache: false,success: function (msg) {if (msg.result) {layer.alert('删除成功', {icon: 1});oDataTable.ajax.reload();} else {//alert(msg.message);layer.alert('删除失败', {icon: 2});}return;}});}});}

CTRL + S 保存并上传

5.4 权限管理配置

请将下面URL数据添加到菜单管理,并授权给【系统管理】角色组:

运行项目测试批量删除和单条删除功能。

至此,项目中已经完成新增、修改、列表、删除的自定义功能,这些类在项目中有相同需求时都可以直接继承使用。

作业:了解YAML语法格式,以及通过python来读取和写入YAML文件

最新最全文档,请关注我的知识星球: https://t.zsxq.com/MBiqJi2(微信中打开链接)
本节文档对应源码版本: https://github.com/RobbieHan/sandboxMP/tree/v2.05
轻量级办公管理系统项目开源地址:https://github.com/RobbieHan/gistandard

实现option上下移动_Django实战2-自动化运维之配置管理-05:字典管理功能实现相关推荐

  1. 自动化运维工具ansible的安装管理以及模块介绍

    自动化运维工具ansible的安装管理以及模块介绍 目录 自动化运维工具ansible的安装管理以及模块介绍 一.ansible概述 1.几种常用运维工具比较 2.Ansible简介 3.Ansibl ...

  2. 【网工手艺】专栏入口(网工学习实战+网络自动化运维探讨)

    哈喽,大家好!第一次在CSDN发文章哈! 我叫朱嘉盛,一名至今依然奋战在一线运维的平凡网工.入行11载,通信网2G守到5G,互联网(城域网)从近乎空白全程参与到百来万用户.一路走来,在网络自动化运维方 ...

  3. 一个颜值低但脾气超好的自动化运维实战入门教程

    注:本教程由廖高祥发布于实验楼,版权归原作者所有. 什么是自动化运维? 自动化运维是指将IT运维中日常的.大量的重复性工作自动化,把过去的手工执行转为自动化操作.自动化运维不单纯是一个维护过程,更是一 ...

  4. 自动化运维工具Ansible实战---常用模块

    Ansible默认提供了很多模块来供我们使用.在Linux中,我们可以通过 ansible-doc -l 命令查看到当前Ansible支持哪些模块,通过 ansible-doc -s [模块名] 又可 ...

  5. python自动化运维书籍推荐_《Python 自动化运维:技术与最佳实践》

    第一部分 基础篇 第1章 系统基础信息模块详解 2 1.1 系统性能信息模块psutil 2 1.1.1 获取系统性能信息 3 1.1.2 系统进程管理方法 6 1.2 实用的IP地址处理模块IPy ...

  6. Python自动化运维-丁志文-专题视频课程

    Python自动化运维-4561人已学习 课程介绍         本职业规划路线是专门为从事运维开发的同学准备的,并且是严格按照企业需求的标准定制的学习路线.路线中包含python基础和进阶,lin ...

  7. 运维技能定级标准第4篇——关于运维工程师岗位的自动化运维与运维开发技能级别设计

    运维工程师岗位工作技能的评定类别(5)和(6) 5.自动化运维技术 级别0,什么都不懂 级别1,了解ansible.saltstack.puppet等主流的自动化运维管理技术工具,掌握公司主要使用的一 ...

  8. 云计算Python自动化运维开发实战 三、python文件类型

    为什么80%的码农都做不了架构师?>>>    云计算Python自动化运维开发实战 三.python文件类型 导语: python常用的有3种文件类型 1. 源代码     py ...

  9. Python+Django+Ansible Playbook自动化运维项目实战(二)

    Python+Django+Ansible Playbook自动化运维项目实战 一.资产管理,自动化发现.扫描 1.服务端资产探测.扫描发现 1)资产管理的资产: 2)抽象与约定: 2.探测协议和模块 ...

最新文章

  1. TVM优化GPU机器翻译
  2. java - 把日志生成到指定目录
  3. 【Selenium】导出成py脚本的基础使用
  4. Bitmap Font生成
  5. Kafka中的配置项参数unclean.leader.election.enable
  6. rfp计算机,RFP(中英文).doc
  7. java hashcode相等_关于java:hashCode实现,用于“等于某些字段相等”
  8. RESTful Web Services简单介绍
  9. MLP 又又又升级了!港大商汤开源首个用于检测与分割任务的MLP架构
  10. 拓端tecdat|R语言广义线性模型(GLMs)算法和零膨胀模型分析
  11. crt是什么意思 windows编程_从零开始,学习windows编程 - hello.c的疑惑!
  12. GJB 软件质量保证报告(模板)
  13. 【胡学长 带你学 Global Mapper 】Global Mapper Pro 23.1 -x64安装教程(附*英*软件包下载)
  14. 这些APP专注于大众的生活,致远互联专注于他们的管理
  15. paddle 图标注_没那么简单,手把手教你用Origin制作XRD谱图!
  16. 机器视觉镜头基础知识详解
  17. 计算机cpu intel,Intel的CPU后面带F是什么意思?
  18. 密码学的安全性浅析3
  19. VS中*.clw *.ncb *.opt *.aps这些文件是做什么用的?
  20. 用Flash做点击页面图片切换效果的超级详细教程

热门文章

  1. java面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
  2. mybatis常用jdbcType数据类型
  3. linux查看正在运行的窗口,获取linux中打开的应用程序窗口的数量
  4. 12面魔方公式图解法_一位建筑工程师:多年渴望就是学会魔方还原,只按这七步就可以!...
  5. mybatis plus当月数据查询_Springboot+mybatis(plus)+druid多数据源
  6. mac玩rust用什么画质_Mac上的活动监视器到底有什么用?你会用么?
  7. 世外桃源六python_六年匠心 桃花源记6月1日全民狂欢
  8. hadoop ubantu环境搭建_ubuntu hadoop学习 环境搭建
  9. java类加载及new对象的过程
  10. mysql sql使用序列_SQL 使用序列