前一章节介绍了List页面的JQuery技术栈的迁移,这一章节我们花一些篇幅来说说修改/查看页面的技术栈迁移。相对于List的获取数据,修改页面涉及到数据Post提交到后台更新数据库。我们仍旧小步迭代的方式推进,修改/查看页面的技术迁移。

1.1. 修改/查看页面分离

  修改/查看页面分离与列表的前后台分离会相对复杂一些,主要时是修改页面会涉及到通过POST向后台提交数据修改。基于模板的方式加载数据,技术上是通过view的change函数里增加POST分支来实现数据提交的,提交成功后重定向加载列表url,我们先沿用这一思路采用前后台分离的模式来重构我们的修改/查看页面。

1.1.1. 修改模板taskChange.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>任务详情</h1>
<div id="task_id"></div>
<div id="task_num"></div>
<form method="post" id="edit_form" hidden>
<input name="source" id="id_source" value="" />
<input name="target" id="id_target" value="" />
<input type="submit" value="提交">
{% csrf_token %}
</form>
<div id="source"></div>
<div id="target"></div>
<div id="state"></div>
<div id="priority"></div>
<div id="begin_date"></div>
<div id="end_date"></div>
<div id="job_count"></div>
<script>
task = {
"TaskId": 2,
"TaskNum": 102,
"Source": "101",
"Target": "05-01-02",
"Barcode": "101001001010",
"State": "处理成功",
"Priority": "紧急",
"BeginDate": null,
"EndDate": null,
"User": 1,
"SystemDate": "2021-01-26 05:59:45",
"JobCount": 10
}
getData()
function getData() {
#① 数据显示绑定的赋值代码
$('#task_id').text(task.TaskId)
$('#task_num').text(task.TaskNum)
$('#source').text(task.Source)
$('#target').text(task.Target)
$('#barcode').text(task.Barcode)
$('#state').text(task.State)
$('#priority').text(task.Priority)
$('#begin_date').text(task.BeginDate)
$('#end_date').text(task.EndDate)
$('#job_count').text(task.JobCount)
}
</script>
</body>
</html>

  标注①:getData函数里,数据显示绑定的赋值代码。

  运行效果

1.1.2. 改造任务获取后台

  接下来,我们通过增加taskGet函数通过传入对象pk来获取对象的json数据。获取数据的url“ http://localhost:8080/task/taskGet/1/”,获取pk=1的model对象数据。

  Task/urls.py文件

from django.urls import path,re_path
from Task import views
urlpatterns = [
...
path('taskGetList/', views.taskGetList,name='taskGetList')
re_path('taskGet/(?P<pk>\d+)/$',views.taskGet,name='taskGet'),#① ]

  标注①:通过传入pk参数来获取单个model的json格式数据。

  Task/urls.py文件

...
def taskGet(request,pk):
model = get_object_or_404(Task, pk=pk)#①
modelJson = model_to_dict(model)
modelJson['SystemDate'] = model.SystemDate.strftime('%Y-%m-%d %H:%M:%S')
modelJson['JobCount'] =model.JobCount() #①
modelJson['Priority'] =model.get_Priority_display()#②
modelJson['State'] =model.get_State_display() return JsonResponse({"model":modelJson,'total':1,'success':True})

  标注①:通过传入pk参数来获取单个model的json格式数据。

  运行结果: http://localhost:8080/task/taskGet/1/

1.1.3. 再次重构taskChange.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>任务详情</h1>
<div id="task_id">{{pk}}</div> <!--①-->
<div id="task_num"></div>
<form method="post" id="edit_form" hidden>
<input name="source" id="id_source" value="" />
<input name="target" id="id_target" value="" />
<input type="submit" value="提交">
{% csrf_token %}
</form>
<div id="source"></div>
<div id="target"></div>
<div id="state"></div>
<div id="priority"></div>
<div id="begin_date"></div>
<div id="end_date"></div>
<div id="job_count"></div> <script>
getData() function getData() {
//异步从后台获得值
url_str = "/task/taskGet/"+ $('#task_id').text() //②
$.ajax({ url: url_str , success: function (result) {
task = result.model
$('#task_num').text(task.TaskNum)
$('#source').text(task.Source)
$('#target').text(task.Target)
$('#barcode').text(task.Barcode)
$('#state').text(task.State)
$('#priority').text(task.Priority)
$('#begin_date').text(task.BeginDate)
$('#end_date').text(task.EndDate)
$('#job_count').text(task.JobCount)
}
});
}
</script>
</body>
</html>

  标注①:模板需要把请求的pk值,赋值到前端组件,这个很重要所有单个对象均是用pk来获取的。 标注②:前端通过页面组件的pk值,异步获取到任务的json格式数据,并加载显示。

  这里我们同样需要改进一下views函数change函数把获取到的pk值,渲染到前端。

@atomic
def change(request,pk):
if request.method=='GET':
return render(request,'Task/taskChange.html',{"pk":pk})#①
elif request.method=='POST':
data={"Source":request.POST['source'],"Target":request.POST['target']}
Task.objects.filter(pk=pk).update(**data) return __reloadTasksPage(request)

  标注①:需要把请求的pk值,传到前端模板,原来是直接传入对象到模板。

  现在访问地址:http://localhost:8080/task/3/change/结果如下图:

1.2. 提交数据

  进一步重构客户端代码,实现可以修改任务为“未处理”状态的源地址和目标地址数据,并提交数据到后台。

<script>
getData()
function getData() {
//异步从后台获得值
url_str = "/task/taskGet/"+ $('#task_id').text() //②
$.ajax({
url: url_str , success: function (result) {
task = result.model
if (task.State == '未处理') {
$('#source').attr('hidden')
$('#target').attr('hidden')
$('#edit_form').removeAttr('hidden')
$('#id_source').val(task.Source)
$('#id_target').val(task.Target) } else {
$('#edit_form').attr('hidden')
$('#source').removeAttr('hidden')
$('#target').removeAttr('hidden')
$('#source').text(task.Source)
$('#target').text(task.Target)
}
$('#task_num').text(task.TaskNum)
$('#barcode').text(task.Barcode)
$('#state').text(task.State)
$('#priority').text(task.Priority)
$('#begin_date').text(task.BeginDate)
$('#end_date').text(task.EndDate)
$('#job_count').text(task.JobCount)
}
});
}
</script>

  运行结果

  至此,我们完成了修改页面客户与服务端的代码分离,从而实现了django模板页的解耦。我们构建了基于django的框架下的客户端、服务端主流的开发模式。

1.3. 异步POST数据

  目前为止我们提交数据仍然是采用模板方式提交的,如何采用ajax post到后台呢?本小节我们着手处理post的异步提交。

1.3.1. 增加taskSave url

  参考前面的views 函数taskGet新增做一个taskSave 并发布url。

from django.urls import path,re_path
from Task import views
urlpatterns = [
...
re_path('taskGet/(?P<pk>\d+)/$',views.taskGet,name='taskGet'),
re_path('taskSave/(?P<pk>\d+)/$',views.taskSave,name='taskSave'),#① ]

  文件:Task/views.py

...
def taskSave(request,pk):
data={"Source":request.POST['source'],"Target":request.POST['target']}
model = Task.objects.filter(pk=pk).update(**data)
data={'total':model,'success':True}
return JsonResponse(data)

1.3.2. 修改页面代码

...
<form method="post" id="edit_form" hidden> <input name="source" id="id_source" value="" />
<input name="target" id="id_target" value="" />
<input type="button" value="提交" onclick="saveData()" > <!--①-->
{% csrf_token %}
</form>

  标注①:修改提交按钮采用JQuery自定义click事件处理数据提交。

<script>
...
function saveData() {
//异步从后台获得值
url_str = "/task/taskSave/"+ $('#task_id').text() + '/' //①
data = {
source: $('#id_source').val(),
target: $('#id_target').val(),
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val() //②
}
$.ajax({
type: 'POST',url: url_str, data: data, success: function (result) {
//alert('HEHE')
window.location.replace("/task/"); //③
}
}); }
</script>

  标注①:数据POST url 例子:/task/taskSave/1/,意思是更新pk=1的model数据。标注②:一定要传回这个参数,否则会报csrf验证失败。标注③:成功修改后从定向url到“/task/”。

1.4. 数据删除

  作为企业开发增/删/改/查,目前为止我们涉及到了查询和修改,另外两个重要的就是新增和删除,通过新增添加数据,通过删除操作删除不需要的数据。

1.4.1. 删除操作

  我们先来说删除操作,与修改的关键是对象标识(pk),同理,删除也是通过对象标识来进行。我们在查看页面增加删除按钮,来完成删除操作。删除某个任务涉及到后台数据的变化,常规采用POST方式来完成数据提交,这里我们把url设计成:/task/taskDel与保存函数类似的范式,但是不在url中显示要删除的pk值,pk作为post参数传递。

  文件:Task/urls.py

from django.urls import path,re_path
from Task import views
urlpatterns = [
...
path('taskGetList/', views.taskGetList,name='taskGetList'),
re_path('taskGet/(?P<pk>\d+)/$',views.taskGet,name='taskGet'),
re_path('taskSave/(?P<pk>\d+)/$',views.taskSave,name='taskSave'),
path('taskDel/',views.taskDel,name='taskDel'),#①
]

  标注①:不在显示传入pk参数,通过post隐式方式传入对象标识。

  文件:Task/views.py

...
def taskDel(request):
data={'total':0,'success':False}
if request.method=='POST':
pk=request.POST['pk']#①
model = Task.objects.filter(pk=pk).delete()
data={'total':model,'success':True} #②
return JsonResponse(data)

  标注①:获取POST请求里的pk参数。标注②:后台接口返回成功与失败,前端来判断后续的处理。

  文件:模板taskChange.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<h1>任务详情</h1>
<div id="task_id">{{pk}}</div>
<div id="task_num"></div>
<form method="post" id="edit_form" hidden> <input name="source" id="id_source" value="" />
<input name="target" id="id_target" value="" />
<input type="button" value="提交" onclick="saveData()" >
<input type="button" value="删除" onclick="delData()" > <!--①-->
{% csrf_token %}
</form>
<div id="source"></div>
<div id="target"></div>
<div id="state"></div>
<div id="priority"></div>
<div id="begin_date"></div>
<div id="end_date"></div>
<div id="job_count"></div>
<script>
getData()
function getData() {
//异步从后台获得值
url_str = "/task/taskGet/" + $('#task_id').text() + '/'
$.ajax({
url: url_str, success: function (result) {
task = result.model
if (task.State == '未处理') {
$('#source').attr('hidden')
$('#target').attr('hidden')
$('#edit_form').removeAttr('hidden')
$('#id_source').val(task.Source)
$('#id_target').val(task.Target)
} else {
$('#edit_form').attr('hidden')
$('#source').removeAttr('hidden')
$('#target').removeAttr('hidden')
$('#source').text(task.Source)
$('#target').text(task.Target)
}
$('#task_num').text(task.TaskNum)
$('#barcode').text(task.Barcode)
$('#state').text(task.State)
$('#priority').text(task.Priority)
$('#begin_date').text(task.BeginDate)
$('#end_date').text(task.EndDate)
$('#job_count').text(task.JobCount)
}
}) } function saveData() {
//异步从后台获得值
url_str = "/task/taskSave/"+ $('#task_id').text() + '/'
data = {
source: $('#id_source').val(),
target: $('#id_target').val(),
csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
}
$.ajax({
type: 'POST',url: url_str, data: data, success: function (result) {
window.location.replace("/task/");
}
});
} function delData() {
//异步从后台获得值
url_str = "/task/taskDel/" //①
data = {
pk: $('#task_id').text(),
csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val()
}
$.ajax({
type: 'POST',url: url_str, data: data, success: function (result) {
window.location.replace("/task/"); //②
}
});
}
</script>
</body>
</html>

  标注①:注意没有传入pk参数。标注②:后台返回成功后,重定向页面到列表页面。

  运行程序,在列表页面点击修改进入修改页面,未处理的任务我就可以点击删除按钮删除这条任务记录了,然后重新定向到列表页面就会发现重新刷新的类别没有那条任务记录了,删除操作成功!

1.5. 运行效果

1.6. 小结

  通过本章节内容,我们完成了从列表到修改界面的服务端与客户端分离的写法,并仍然采用稳步的渐进式改造方案,采用小步快跑的方式完成本次迭代。最后,我们在功能不变的前提下,完成了技术栈的迁移,把基于模板页渲染的django变成了基于模板框架js异步渲染的主流编程模式。通过例子完整的演示了django如何实现企业开发中遇到“增/删/查/修/”后面3个问题,新增相对较为复杂,我们留给下一章节来重点讲述。

python工业互联网应用实战16-前后端分离模式之修改与删除的更多相关文章

  1. python工业互联网应用实战18—前后端分离模式之jquery vs vue

    前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...

  2. python工业互联网应用实战17—前后端分离模式之django template vs jquery3

    上一章节我们完成了"CRUD"的后面3个功能点,新增由于改动较大我们专门增加本章来阐述,主要是完成技术栈切换后,会发现模板的代码判断过多,逻辑过于复杂.对未来存在的扩展和维护友好性 ...

  3. Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期

    一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...

  4. AngularJS中在前后端分离模式下实现权限控制 - 基于RBAC

    一:RBAC 百科解释: 基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到广泛的关注.在RBAC中,权限与角色相关联,用 ...

  5. python工业互联网应用实战15-前后端分离模式1

    我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...

  6. Vue的学习总结之---Vue项目 前后端分离模式解决开发环境的跨域问题

    原文:https://blog.csdn.net/localhost_1314/article/details/83623526 在前后端分离的web开发中,我们与后台联调时,会遇到跨域的问题. 比如 ...

  7. python工业互联网应用实战2—从需求开始

    前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...

  8. python工业互联网应用实战3—模型层构建

    本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...

  9. python工业互联网应用实战1—SQL与ORM

    从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题. ...

随机推荐

  1. Python面向对象的高级编程

    数据封装.继承和多态只是面向对象程序设计中最基础的3个概念.在Python中,面向对象还有很多高级特性,允许我们写出非常强大的功能. 我们会讨论多重继承.定制类.元类等概念. 使用__slots__ ...

  2. Maven导入依赖慢解决办法

    新安装的Maven,下载jar包速度会很慢,因为官方的库在国外, 连上并下载速度很慢. 因为maven是支持镜像的,我们就可以本地maven目录下的的conf目录下的setting.xml文件中找到标 ...

  3. 解决Spring中使用Example无法查询到Mongodb中的数据问题

    1 问题描述 在Spring Boot中使用Mongodb中的Example查询数据时查询不到,示例代码如下: ExampleMatcher matcher = ExampleMatcher.matc ...

  4. PE结构分析(二)

    在表中,我们知道了0x01 4c对应的平台结构是i386: 我们接着分析下一个字段,给出PE结构图 向后推移2个字节,现在来到(图片高亮部分): 高亮部分对应IMAGE_NT_HEADERS结构的Nu ...

  5. 开坑:mysql相关问题

    一. 先过滤后连表和先连表后在mysql中选择的哪一种? 二. left join 和inner join使用场景有什么区别? 三. 第二个问题的衍生问题:left join中where 条件使用对n ...

  6. Jenkins 自动触发执行的配置

    1. 两种触发方式 2. jenkins 和 github 同步配置 ngrok 安装 webhook 配置 1. 两种触发条件 Jenkins 中建立的任务是可以设置自动触发,更进一步的实现自动化. ...

  7. css选择器中:first-child 与 :first-of-type的区别

    ## css选择器中:first-child 与 :first-of-type的区别 ---- :first-child选择器是css2中定义的选择器,从字面意思上来看也很好理解,就是第一个子元素.比 ...

  8. 【SpringBoot】Springboot2.x整合Redis(一)

    备注: springboto整合redis依赖于spring-boot-starter-data-redis这个jar 一,项目环境和依赖 1.POM.xml配置 <parent> < ...

  9. PAT 乙级 -- 1013 -- 数素数

    题目简介 令Pi表示第i个素数.现任给两个正整数M <= N <= 104,请输出PM到PN的所有素数. 输入格式: 输入在一行中给出M和N,其间以空格分隔. 输出格式: 输出从PM到PN ...

  10. UVA10943简单递推

    题意:      给你两个数字n,k,意思是用k个不大于n的数字组合(相加和)为n一共有多少种方法? 思路:       比较简单的递推题目,d[i][j]表示用了i个数字的和为j一共有多少种情况,则 ...