通常页面要能对资源进行增删改查,对应http的 POST、DELETE、UPDATE、GET

页面显示使用了layui,而layui的表格有自己的数据获取方式,所以我们的视图要做一些调整,不使用后端渲染,只返回数据

具体的实现是页面点击按钮或者导航后,服务端渲染一个空的页面,剩下的数据由页面的js驱动获取。

返回空页面的视图:

from django.views import generic

class ServicePageView(generic.ListView):
template_name = 'microservice/service.html' def get_queryset(self):
pass

对应的urls:

url(r'^home/$', views.ServicePageView.as_view()),

空页面模板,这里的空指的是内容为空,模板还是有js的,

templates/microservice/service.html:

<table class="layui-hide" id="service-list-table" lay-filter="tableEvent"></table>
<script src="/static/js/layui/layui.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/layui.css" />
<script>
layui.use(['laypage', 'layer', 'form', 'table'], function () {
var laypage = layui.laypage //分页
, layer = layui.layer //弹层
, table = layui.table
;
//执行一个 table 实例
table.render({
elem: '#service-list-table'
, url: '{% url "api_microservice" %}' //数据接口
, cellMinWidth: 80 //全局定义常规单元格的最小宽度,layui 2.2.1 新增
,autoSort: false //禁用前端自动排序
, page: {
curr: 1
, limit: 20
, limits: [20, 30, 40, 50, 100]
, layout: ['count', 'prev', 'page', 'next', 'limit', 'skip']
, jump: function (obj) {
console.log(obj)
}
}
, cols: [[ //表头
{field: 'name', title: 'service名称', sort: true, minWidth: 120}
, {field: 'language', title: '语言类型', width: 100}
, {field: 'description', title: '描述', minWidth: 150}
]]
, id: 'serviceListTable'
}); /*
* 表格搜索与重载
*/
var $ = layui.$, active = {
reload: handleReloadTable
};
// 重载
function handleReloadTable(){
$.ajax({
url: '{% url "api_microservice" %}',
type: "GET",
dataType: "json",
}).done(result => {
table.reload('serviceListTable', {
page: {
curr: 1 //重新从第 1 页开始
}
});
}).fail((xhr, status, error) => { })
}
</script>

服务管理视图

RESTful风格的api通常设计如下:

GET api/resources 返回数据列表

POST api/resources 则是创建一条记录

UPDATE api/resources/{id} 更新一条记录

DELETE api/resources/{id} 删除一条记录

将获取、创建的方法放在一个视图,修改、删除是另外一个视图

查找

from django.http import JsonResponse
from django.core.paginator import Paginator
from django.utils.timezone import utc, localtime
from microservice.models import * class ServiceApi(generic.View):
"""
服务管理操作 获取列表、添加
"""
def get(self, request):
query = request.GET
page = query.get('page', 1)
limit = query.get('limit', 20) services = Service.objects.select_related('updated_by')
paginator = Paginator(services, limit)
pdata = paginator.page(page) data = [{
'id': item.id,
'name': item.name,
'description': item.description,
'language': item.language,
'build_orig': item.build_orig,
'build_url': item.build_url,
'updated_by': item.updated_by.username,
'updated': localtime(item.updated).strftime('%Y-%m-%d %H:%M:%S %Z'),
} for item in pdata] return JsonResponse({
'data': data,
'count': services.count(),
'code': 0
})

对应的urls:

url(r'^microservice/$', views.ServiceApi.as_view(), name='api_microservice'),

使用 python manage.py shell 打开控制台,新建几个服务,然后启动django,打开 http://127.0.0.1:8000/home/ ,就能看到页面如下:

创建服务

通过该页面只能进行服务的查看,接下来添加服务新增功能,在 ServiceApi 里增加 post 方法:

    def post(self, request):
d = {}
d['name'] = request.POST.get('name', '')
d['language'] = request.POST.get('language', 'cpp')
d['description'] = request.POST.get('description', '')
d['build_orig'] = request.POST.get('build_orig', 'git')
d['build_url'] = request.POST.get('build_url', '') if not d['name'] or not d['build_url']:
return JsonResponse({'msg': '必填项不能为空'}, status=417) try:
Service.objects.get(name=d['name'])
except Service.DoesNotExist:
d['created_by'] = request.user
d['updated_by'] = request.user
service = Service.objects.create(**d)
return JsonResponse({}, status=201)
else:
return JsonResponse({'msg': '该服务已存在'}, status=409)

相应的页面也要做一些修改,以下内容添加到 templates/microservice/service.html 头部

<div class="layui-row">
<div class="layui-col-md2 layui-col-md-offset4">
<button id="create-form-button" class="layui-btn" style="float: right;">
<i class="layui-icon layui-icon-add-1"></i> 添加
</button>
</div>
</div> <!-- 需要弹出的添加界面 -->
<div class="layui-row" id="service-create" style="display: none;">
<div class="layui-col-md10">
<form id="service-create-form" class="layui-form" lay-filter="create"> <!-- 提示:如果你不想用form,你可以换成div等任何一个普通元素 -->
<div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 名称</label>
<div class="layui-input-block">
<input type="text"
name="name"
placeholder="请输入服务名称"
autocomplete="off"
class="layui-input"
lay-verify="name"
/>
</div>
</div> <div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 语言类型</label>
<div class="layui-input-block" >
<input type="radio" lay-filter="create-lauguage" name="language" value="cpp" title="cpp" checked>
<input type="radio" lay-filter="create-lauguage" name="language" value="go" title="go" >
<input type="radio" lay-filter="create-lauguage" name="language" value="other" title="其它" >
</div>
</div> <div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 构建来源</label>
<div class="layui-input-block">
<input type="radio" name="build_orig" value="git" title="git" checked>
</div>
</div> <div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 构建地址</label>
<div class="layui-input-block">
<input type="text"
name="build_url"
placeholder="请输入构建地址"
autocomplete="off"
class="layui-input"
lay-verify="build_url"
/>
</div>
</div> <div class="layui-form-item layui-form-text">
<label class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea rows="5" name="description" placeholder="请输入内容" class="layui-textarea"></textarea>
</div>
</div> <div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary my-cancel-button">取消</button>
<button class="layui-btn" lay-submit="" lay-filter="create-form">立即提交</button>
</div>
</div> </form>
</div>
</div>

页面增加相关js代码:

      /*
* 监听表格事件
*/
// 排序事件
table.on('sort(tableEvent)', function(obj){
table.reload('serviceListTable', {
initSort: obj //记录初始排序,如果不设的话,将无法标记表头的排序状态。
,where: { //请求参数(注意:这里面的参数可任意定义,并非下面固定的格式)
sort_field: obj.field //排序字段
,order: obj.type //排序方式
}
});
}); table.on('tool(tableEvent)', function (obj) {
//注:tool 是工具条事件名,tableEvent 是 table 原始容器的属性 lay-filter="对应的值"
var data = obj.data //获得当前行数据
, layEvent = obj.event; //获得 lay-event 对应的值
if (layEvent === 'del') {
handleDelete(obj);
} else if (layEvent === 'edit') {
handleModify(obj);
}
}); function handleCreate(layerIdx, postdata) {
var loadingLayerIdx = layer.load(2, {
shade: [0.3]
});
$.ajax({
url: '{% url "api_microservice" %}',
type: "POST",
dataType: "json",
data: postdata,
}).done(result => {
layer.msg('提交成功', {
icon: 1,
time: 1000 //2秒关闭(如果不配置,默认是3秒)
}, function () {
handleReloadTable();
layer.close(layerIdx);
});
}).fail((xhr, status, error) => {
// 移除disabled属性 提交按钮可点击
$('#service-create-form button[lay-submit]').removeClass('layui-btn-disabled');
ajaxErrorHandle(xhr, status, error);
}).always(() => {
// close loading
layer.close(loadingLayerIdx);
})
return false;
} $('#create-form-button').click(function () {
/* 再弹出添加界面 */
var layerIdx = layer.open({
type: 1,
title: '新增',
area: ["50%", "70%"],
content: $("#service-create").html(),
shadeClose: true, // 点击弹出层的shade可关闭弹出层
success: () => {
// 移除disabled属性
$('#service-create-form button[lay-submit]').removeClass('layui-btn-disabled');
}
}); // 取消时关闭弹出层
$('#service-create-form .my-cancel-button').click(() => {
layer.close(layerIdx);
return false; // 阻止浏览器自动跳转
})
/* 渲染表单 */
form.render(null, 'create');
form.verify({
name: (value) => {
let val = value.trim();
if (!val) {
return '服务名不能为空';
}
if (!/[/^[\w.\-_]{3,40}$/.test(val)) {
return '3~40个字符, 大小写字母数字和下划线小数点'
}
}
, language: (value) => {
let val = value.trim();
if (!val) {
return '不能为空';
}
}
, build_url: (value) => {
let val = value.trim();
if (!val) {
return '不能为空';
} else if (!(val.startsWith('http://') || val.startsWith('https://'))) {
return 'url地址格式不正确,必须以http/https开头';
}
} });
//监听提交
form.on('submit(create-form)', function (data) {
$(this).addClass('layui-btn-disabled');
handleCreate(layerIdx, data.field);
return false; // 阻止浏览器自动跳转
});
});

修改和删除

视图:

class ServiceManageApi(BaseApiView):
"""
服务管理操作 修改、删除
""" def post(self, request, pk):
params = request.POST
d = {}
d['description'] = params.get('description', '')
d['language'] = params.get('language', '')
d['build_url'] = params.get('build_url', '')
d['updated_by'] = request.user
d['updated'] = datetime.datetime.utcnow().replace(tzinfo=utc) try:
Service.objects.filter(pk=pk).update(**d)
except Service.DoesNotExist:
return JsonResponse({'msg': '资源不存在'}, status=404)
return JsonResponse({}) def delete(self, request, pk):
svcs = Service.objects.annotate(num_versions=Count('microserviceversion')).filter(pk=pk)
if not svcs:
return JsonResponse({'msg': '资源不存在'}, status=404)
if len(svcs) > 1:
return JsonResponse({'msg': '数据错误'}, status=417)
if svcs[0].num_versions != 0:
return JsonResponse({'msg': '该服务有关联的版本,不允许删除'}, status=417) svcs.delete()
return JsonResponse({})

对应的urls:

url(r'^microservice/(?P<pk>[0-9]+)/$', views.ServiceManageApi.as_view(), name='api_microservice_manage'),

在页面table的后面增加操作,支持 修改删除

<script type="text/html" id="barDemo">
<a class="layui-btn layui-btn-xs layui-btn-primary" lay-event="edit">编辑</a>
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
</script> <!-- 修改 -->
<div class="layui-row" id="service-modify" style="display: none;">
<div class="layui-col-md10">
<form id="service-modify-form" class="layui-form" lay-filter="modify">
<div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 名称</label>
<div class="layui-input-block">
<input type="text"
name="name"
placeholder="请输入服务名称"
autocomplete="off"
class="layui-input"
lay-verify="name"
disabled=""
style="background-color: #eee; cursor: not-allowed;"
/>
</div>
</div> <div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 语言类型</label>
<div class="layui-input-block">
<input type="radio" name="language" value="cpp" title="cpp" disabled>
<input type="radio" name="language" value="go" title="go" disabled>
<input type="radio" name="language" value="other" title="其它" disabled>
</div>
</div> <div class="layui-form-item">
<label class="layui-form-label"><i class="layui-icon layui-icon-rate" style="color: red;"></i> 构建地址</label>
<div class="layui-input-block">
<input type="text"
name="build_url"
placeholder="请输入构建地址"
autocomplete="off"
class="layui-input"
lay-verify="build_url"
disabled=""
style="background-color: #eee; cursor: not-allowed;"
/>
</div>
</div> <div class="layui-form-item layui-form-text">
<label class="layui-form-label">描述</label>
<div class="layui-input-block">
<textarea rows="5" name="description" placeholder="请输入内容" class="layui-textarea"></textarea>
</div>
</div> <div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary my-cancel-button">取消</button>
<button class="layui-btn" lay-submit="" lay-filter="modify-form">保存修改</button>
</div>
</div> </form>
</div>
</div>

相应的js:

// 渲染表格的cols里增加
, {fixed: 'right', title: '操作', width: 300, align: 'center', toolbar: '#barDemo'}
/*
* 编辑 删除
*/
function handleDelete(obj) {
layer.confirm('确定删除?删除后不可恢复!', {icon: 0, title:'提示'}, function (index) {
layer.close(index);
var loadingLayerIdx = layer.load(2, {
shade: [0.3]
});
var url = '{% url "api_microservice_manage" 0 %}';
url = url.substr(0, url.lastIndexOf(0));
url += obj.data.id + '/';
$.ajax({
url: url,
type: "DELETE",
}).done(result => {
layer.msg('删除成功', {icon: 1});
obj.del(); //删除对应行(tr)的DOM结构
}).fail((xhr, status, error) => {
layer.msg('删除失败: ' + (xhr.status >= 500 ? '服务器内部错误' : xhr.responseJSON.msg), {icon: 2});
}).always(() => {
layer.close(loadingLayerIdx);
});
})
} function handleModify(obj) {
/* 弹出修改界面 */
var data = obj.data;
var layerIdx = layer.open({
type: 1, // 0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title: '修改服务',
area: ["50%", "70%"],
content: $("#service-modify").html(),
shadeClose: true, // 点击弹出层的shade可关闭弹出层
success: () => {
// 移除disabled属性 提交按钮可点击
$('#service-modify-form button[lay-submit]').removeClass('layui-btn-disabled');
}
}); // 取消时关闭弹出层
$('#service-modify-form .my-cancel-button').click(() => {
layer.close(layerIdx);
return false; // 阻止浏览器自动跳转
})
//表单初始赋值
form.val('modify', {
"name": data.name // "name": "value"
,"language": data.language
,"build_orig": data.build_orig
,"build_url": data.build_url
,"description": data.description
}) /* 渲染表单 */
form.render(null, 'modify');
form.render('select', 'modify'); form.verify({
build_url: (value) => {
let val = value.trim();
if (!val) {
return '不能为空';
} else if (!val.startsWith('http://') || !val.startsWith('https://')) {
return 'url地址格式不正确,必须以http/https开头';
}
}
});
//监听提交
form.on('submit(modify-form)', function (data) {
$(this).addClass('layui-btn-disabled');
var loadingLayerIdx = layer.load(2, {
shade: [0.3]
});
var url = '{% url "api_microservice_manage" 0 %}';
url = url.substr(0, url.lastIndexOf(0));
url += obj.data.id + '/'; $.ajax({
url: url,
type: "POST",
dataType: "json",
data: data.field, }).done(result => {
layer.msg('提交成功', {
icon: 1,
time: 1000 //2秒关闭(如果不配置,默认是3秒)
}, function () {
layer.close(layerIdx);
handleReloadTable(false);
});
}).fail((xhr, status, error) => {
// 移除disabled属性 提交按钮可点击
$('#service-modify-form button[lay-submit]').removeClass('layui-btn-disabled');
layer.msg('提交失败: ' + (xhr.status >= 500 ? '服务器内部错误' : xhr.responseJSON.msg), {icon: 2});
}).always(() => {
layer.close(loadingLayerIdx);
})
return false;
});
}

页面效果图:

相关的代码在 这里

Django实现自动发布(2视图-服务管理)的更多相关文章

  1. Django实现自动发布(2视图-服务版本查找和新增)

    前面做好了服务的管理,接下来是服务版本的管理,和服务类似,版本也有增删改查.先在服务的管理页面做一个入口,如下图: 需要在上一步的服务管理页面增加按钮.按钮方法,点击按钮跳转时要打开一个新的页面,所以 ...

  2. Django实现自动发布(2视图-任务接收)

    上一篇服务版本的新增,是通过触发 gitlab 任务来实现的,那么如何得到任务的最终状态呢? 好在 gitlab 为我们提供了webhook,也就是消息钩子,可以发送pipeline消息到我们指定的地 ...

  3. 解决GP服务产生的结果无法自动发布为地图服务的问题

    在ArcGIS for Javascript API或REST API调用GP服务时,常常会遇到这样一种情况:GP服务运行以后,执行成功,也能够生成结果,然而结果并没有直接产生动态的地图服务供API调 ...

  4. Django实现自动发布(1数据模型)

    公司成立之初,业务量较小,一个程序包揽了所有的业务逻辑,此时服务器数量少,上线简单,基本开发-测试-上线都是由开发人员完成. 随着业务量逐渐上升,功能增多,代码量增大,而单一功能上线需要重新编译整个程 ...

  5. Django实现自动发布(3发布-升级和回退)

    发布实际上就是将服务的某个版本和一台主机关联,我用一张表(MicroServiceInstance)记录了主机id.服务id.版本id,目前一台主机只能部署一个版本,所以主机id和服务id要做联合索引 ...

  6. Django实现自动发布(3发布-安装)

    相对于服务的升级.回退,新部署一个服务要复杂一些,要满足以下要求: 已经运行了服务实例的主机不能重复部署 进程启动需要的配置文件要先同步到主机上 之前的升级.回退都是指进程的操作,不涉及配置文件的变更 ...

  7. 使用Jenkins自动发布Windows服务项目

    不同于发布Web项目,自动发布Windows服务项目需要解决以下几个问题: 如何远程停止和开启服务?需要在发布前停止服务,在发布完成后开启服务. 如何上传编译文件到目标服务器? 问题1:如何远程停止和 ...

  8. GeoServer自动发布地图服务

    1 NetCDF气象文件自动发布案例 GeoServer是一个地理服务器,提供了管理页面进行服务发布,样式,切片,图层预览等一系列操作,但是手动进行页面配置有时并不满足业务需求,所以GeoServer ...

  9. Rainbond v5.1.2发布,微服务架构应用便捷管理和交付

    Rainbond v5.1.2发布,微服务架构应用便捷管理和交付 Rainbond是开源的企业应用云操作系统,支撑企业应用的开发.架构.交付和运维的全流程,通过无侵入架构,无缝衔接各类企业应用,底层资 ...

随机推荐

  1. CSS3 完善盒模型

    CSS3 改善了传统盒模型结构,增强了盒子构成要素的功能,扩展了盒模型显示的方式. 改善结构:为盒子新增轮廓区: 增强功能:内容区增强 CSS 自动添加内容功能,增强内容移除.换行处理:允许多重定义背 ...

  2. Android-----WebView加载HTML界面布局并进行数据交互

    注:在做例子之前要先做好准备工作,在app下新建一个名为:assets的目录(不懂怎么创建的可参考:https://blog.csdn.net/Biegral/article/details/4717 ...

  3. CDA数据分析【第一章:数据分析概述】

    一.数据分析行业发展 1.如何收集.保存.管理.分析.共享正在呈指数式增长的数据是我们必须要面对的一个重要挑战. 2.数据分析包括数据采集.数据存储.检查.清洗.分析.转换和建模等方法对数据进行处理的 ...

  4. 在windows 10 64位系统下安装TensorFlow

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/mao_hui_fei/article/de ...

  5. kbmmw 中的Boyer-Moore算法

    kbmmw 5.10 版本中实现了一个非常好用的字符串搜索算法,即Boyer-Moore算法. 在用于查找子字符串的算法当中,BM(Boyer-Moore)算法是目前被认为最高效的字符串搜索算法, 它 ...

  6. Golang: 解析JSON数据之二

    上次我们介绍了 Go 语言中序列化和反序列化 JSON 数据的两个方法 Marshal() 和 Unmarshal(),并以示例演示了它们的用法. 我们在例子中看到,需要事先声明好对应的结构体,才能跟 ...

  7. 关于IE环境下按回车键会自动触发button 按钮的点击事件的解决方案

    今天项目中遇到IE不兼容的问题,于是就根据问题进行修改,修改过程中发现,在输入框内用扫码枪扫描东西后会自动执行页面下面的button按钮,但是其它浏览不会出现这样的问题. 解决方案: 1.用a标签 2 ...

  8. JAVA分页工具类

    最近写了一个代码生成工具,分享下该工具下的分页工具 一.分页工具类 package com.qy.code.api.page; import java.io.Serializable; import ...

  9. ARM架构体系

    架构 处理器家族 ARMv1 ARM1 ARMv2 ARM2.ARM3 ARMv3 ARM6, ARM7 ARMv4 StrongARM.ARM7TDMI.ARM9TDMI ARMv5 ARM7EJ. ...

  10. zabbix--基础概念及原理

    zabbix 基础概念及工作原理整理 什么是 zabbix? Zabbix 能监控各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位.解决存在的各种问题.是一个基于 W ...