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

7d4870bbba6a79707ce1d1913cf61a46.png
本节内容主要实现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数据内容:

13463dae390c13110e3373d7f26b5576.png

运行项目,登陆系统,访问菜单管理页【系统】→ 【权限管理】→ 【菜单管理】,按照上面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数据添加到菜单管理,并授权给【系统管理】角色组:

0e2864c4edfd0392e038f8b43b65439f.png

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

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

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数据添加到菜单管理,并授权给【系统管理】角色组:

eca3d3c0471cf37d6e9fdab69d777134.png

3.6 后端分页功能测试

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

f0a83e5d09cbb125a356afe9ea29c9bb.png

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

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

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

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

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

01fc2bfe3cd6cfe2e3fa0194d70ea592.png

对照自定义的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数据添加到菜单管理,并授权给【系统管理】角色组:

0f9763245692729da0d59ffc0146c57f.png

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

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数据添加到菜单管理,并授权给【系统管理】角色组:

c770b7b29ed30f97a53744801db7b866.png

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用计算机对话的小品,爆笑小品剧本台词《作弊记》

小品深入生活&#xff0c;贴近生活&#xff0c;体验生活&#xff0c;从生活中找灵感。要用艺术的眼光去发现题材&#xff0c;挖掘题材。人物&#xff1a; 学生甲 学生乙 监考教师(教室门前)(甲乙边走边聊&#xff0c;乙背着书包&#xff0c;甲两手空空&#xff0c;只在上衣贴胸…

python queue查询空_【Python】多线程爬虫案例

爬取博客园文章列表爬取博客园文章列表&#xff0c;假设页面的URL是https://www.cnblogs.com/loaderman 要求&#xff1a;使用requests获取页面信息&#xff0c;用XPath / re 做数据提取 获取每个博客里的标题&#xff0c;描述&#xff0c;链接地址&#xff0c;日期等保存到 js…

美国计算机科学联赛获奖,【竞赛获奖】西安高新一中国际班学子在2018-2019美国计算机科学联赛 (ACSL)积分赛中创造历史!...

西安高新一中国际班学子在2018-2019美国计算机科学联赛(ACSL)积分赛中创造历史2018-2019美国计算机科学联赛 (ACSL)积分赛喜讯传来&#xff01;此次竞赛共有来自全国109所重点中学和国际学校的近500同学参赛。在此次竞赛中&#xff0c;中国赛区共有17名同学获得个人最高分奖&am…

5单个编译总会编译全部_JDBC【5】 JDBC预编译和拼接Sql对比

在jdbc中&#xff0c;有三种方式执行sql&#xff0c;分别是使用Statement(sql拼接)&#xff0c;PreparedStatement(预编译)&#xff0c;还有一种CallableStatement(存储过程)&#xff0c;在这里我就不介绍CallableStatement了&#xff0c;我们来看看Statement与PreparedStateme…

计算机怎样旋转桌面,win7电脑怎么设置翻转屏幕

在深度win7之中使用投影仪或者是一些外置视频输出设备的时候&#xff0c;用户可能会有翻转屏幕的需求。那么大家知道win7电脑怎么设置翻转屏幕吗?今天学习啦小编与大家分享下win7电脑设置翻转屏幕的具体操作步骤&#xff0c;有需要的朋友不妨了解下。win7电脑设置翻转屏幕方法…

从入门到精通 pdf_【推荐】铅笔素描从入门到精通pdf|素描基础教程电子书下载!...

铅笔素描从入门到精通pdf|素描基础教程电子书下载&#xff01;铅笔素描从入门到精通pdf|素描基础教程电子书下载&#xff01;铅笔素描从入门到精通pdf|素描基础教程电子书下载&#xff01;如果你的基础太薄弱&#xff0c;不建议自己瞎摸索&#xff0c;你可以关注一下公众号&…

参数估计_状态估计的基本概念(1)参数估计问题

&#xff08;1&#xff09;参数估计问题定义如果一个系统的参数随时间而改变&#xff0c;那么称它为“时变的参数”&#xff1b;如果系统的参数不随时间而改变&#xff0c;那么称它为“时不变的参数”。对参数 &#xff08;时不变&#xff09;的估计问题定义如下&#xff1a;其…

计算机管理内默认共享,关于Windows的默认共享介绍

C:\Documents and Settings\Administrator>net share ?此命令的语法是:NET SHAREsharenamesharenamedrive:path [/GRANT:user,[READ | CHANGE | FULL]][/USERS:number | /UNLIMITED][/REMARK:"text"][/CACHE:Manual | Documents| Programs | BranchCache | None]…

中绘制折线_漂亮图表也可信手拈来,一文学会用Python绘制堆积折线图

今天咱们还是接着上次的话题&#xff0c;继续和大家聊聊关于Python绘图相关的东东哦&#xff0c;上次已经和大家讨论完了如何给自己所绘制的图表中添加装饰线以及修改装饰线密度的方法&#xff0c;今天呢&#xff0c;咱们再聊点的新的东东哦&#xff0c;还是和大家继续深耕Pyth…

计算机电缆对绞节距,DJYPVP阻燃计算机电缆32/0.2芯数直径

电缆敷设在既有正压力作用又有拉力作用的场合(如水中、垂直竖井或落差较大的土壤中)&#xff0c;应选用具有内钢丝铠装的结构型。外护套外护套是保护电线电缆的绝缘层防止环境因素侵蚀的结构部分。外护套的主要作用是提高电线电缆的机械强度、防化学腐蚀、防潮、防水浸人、阻止…

软件测试条件组合覆盖三角形,软件测试三角形问题(覆盖测试)

软件测试三角形问题(覆盖测试) (9页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;9.9 积分成绩辽宁工程技术大学上机实验报吿课程名称软件测试与评估实验题目基于覆盖测试技术院系软件学院专业软件工…

软件测试报告费计什么科目,软件记什么会计科目

1软件记什么 会计 科目会计学的研究对象包括会计的所有方面&#xff0c;如会计的性质、对象、职能、任务、方法、程序、组织&#xff0c;制度、技术等。会计学用自己特有的概念和理论&#xff0c;概括和总结它的研究对象。接下来小编就告诉你软件记什么会计科目。根据《企业会计…

php mysql 统计_PHP和MySQL实现优化统计每天数据

在互联网项目中&#xff0c;对项目的数据分析必不可少。通常会统计某一段时间内每天数据总计变化趋势调整营销策略。下面来看以下案例。案例在电商平台中通常会有订单表&#xff0c;记录所有订单信息。现在我们需要统计某个月份每天订单数及销售金额数据从而绘制出如下统计图&a…

专科计算机专业能报考南方电网,大学毕业想进国家电网?3大条件不可或缺!专科生也有报考机会...

国家电网是许多学子心目中理想的工作&#xff0c;每年的毕业季都有国家电网进入校园招聘。同时每年报考国家电网的人数大概在40万左右&#xff0c;今天&#xff0c;小编就来带大家盘点一下&#xff0c;报考国家电网需要满足哪些条件&#xff0c;方便大四学生对照要求&#xff0…

mysql 5.6 command line client闪退_MySQL 5.6 Command Line Client 点开闪退解决方法

先看下连接mysql本地库的2种方式。第一种运行cmd&#xff0c;键入mysql -uroot -p,如果提示mysql不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。就将mysql的安装路径添加的系统的环境变量中。连接成功的界面如下第二种方式&#xff1a;安装程序中搜索mysql找…

centos7安装mysql的rpm_Centos7 安装MySQL(rpm方式)

1 软件准备(我的网盘链接&#xff1a;https://pan.baidu.com/s/1c2AS6uG 密码&#xff1a;e1sj)mysql-5.6.29-1.el7.x86_64.rpm-bundle.zip Centos7 (我遇到的坑 &#xff1a;用cnetos6.5mini版的时候很难找到依赖&#xff0c;网上可靠的资料不多&#xff0c;结果安装了一大…

计算机重启很慢,电脑重启慢的原因

电脑重启慢的原因电脑开机速度慢是现在比较常见的一个问题&#xff0c;但是有时候重启也很慢&#xff0c;那么&#xff0c;电脑重启慢的原因是什么?下面跟小编一起来了解一下吧!电脑重启慢的原因1、遭到木马病毒入侵&#xff0c;系统遭到破坏和修改&#xff0c;导致程序运行缓…

两个图片叠加在一起css,css两张图片怎么叠加在一起?

css实现两张图片叠加在一起的方法&#xff1a;首先添加2个img标签&#xff1b;然后设置它们的css样式为position:absolute&#xff1b;最后设置其中一个img样式为left:120px即可看见效果。使用css把两个图片叠加&#xff0c;可以通过position定位属性设置两张图片的位置来实现叠…

css背景从左到右颜色渐变,CSS:linear-gradient()背景颜色渐变

background: linear-gradient(direction,color-stop1,color-stop2,...);direction&#xff1a;用角度值指定渐变的方向(或角度)&#xff1b;color-stop1,color-stop2,...&#xff1a;用于指定渐变的起止颜色ps&#xff1a;至少需要两种颜色1 background: -webkit-linear-gradie…

WordPress文章ajax,使用ajax在WordPress后台删除文章方法

今天wpmee小编分享使用ajax在WordPress后台删除文章方法&#xff0c;直接上代码&#xff0c;将下面的代码添加到当前启用的WordPress主题的functions.php里面。// 后台 文章列表 ajax删除文章add_action( admin_footer, dahuzi_custom_internal_javascript );function dahuzi_c…