zoukankan      html  css  js  c++  java
  • python工业互联网应用实战12—客户端操作

      本章节我们将实现与admin里类似的列操作“下达”功能,演示客户端是如何实现操作功能,同时,演示也会强调一点,何时合并你的功能代码,避免相同功能使用不同的代码段来实现,在企业开发中非常重要,良好的编程习惯会让你在未来的维护和扩展中体会到什么叫“好的代码”。

    1.1. Table增加操作列

      本例中我们采用url http://localhost:8001/task/1/start/ 来相应对某行任务执行“下达”操作,类似RESTful的接口模式后面的动词代码某个操作,现在在table中增加一列操作,每行显示下达操作链接,代码如下:

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <table>
            <tr>
                <th>ID</th>
                <th>任务号</th>
                <th>源地址</th>
                <th>目标地址</th>
                <th>条码</th>
                <th>状态</th>
                <th>优先级</th>
                <th>开始时间</th>
                <th>结束时间</th>
                <th>作业数量</th>
                <th>操作</th>
            </tr>
            {% for task in tasks %}
    
            <tr>
                <td>{{task.TaskId }}</td>
                <td>{{task.TaskNum}}</td>
                <td>{{task.Source}}</td>
                <td>{{task.Target}}</td>
                <td>{{task.Barcode}}</td>
                <td>{{task.get_State_display}}</td>
                <td>{{task.get_Priority_display}}</td>
                <td>-</td>
                <td>-</td>
                <td>{{task.job_set.count}}</td>
                <td><a href="{{task.TaskId }}/start/">下达</a></td>
            </tr>
            {%endfor%}
        </table>
    
    
    </body>
    </html>

      运行效果:

    1.2. Task APP增加相应urlviews函数

      接下来在Task urls.py文件里增加“/1/start/”发布下达的url,代码如下:

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

      标注①:正则表达式,来实现Task_id/start/,针对某个对象标识id执行下达命令。

       接下来在Task/views.py文件里添加start函数代码。

    from django.shortcuts import get_object_or_404
    from django.shortcuts import redirect
    from django.db.transaction import atomic
    
    from .TaskBiz import TaskBiz,Task
    
    @atomic
    def start(request,pk):
    
        obj = get_object_or_404(Task, pk=pk)#
        biz= TaskBiz()
        biz.task_start(obj)#
         
        #重新刷新列表界面
        co_path = request.path.split('/')
        new_path=co_path[0:2]
        new_path='/'.join(new_path)
        request.path = new_path
        return redirect(new_path)

      标注①:通过主键获取到任务对象。

      标注②:对获取的任务对象,执行业务逻辑层的task_start函数,这里的业务逻辑直接沿用admin重构组织的那个TaskBiz.py业务逻辑类里的任务“下达”函数。

      章节到这里我希望读者能够体会到代码重用的好处,把业务抽象出一个单独的层,比放在admin里是不是有优势多了,不需要在客户端的“下达”时重新再实现一遍这个功能。

      点击操作列里的下达链接,任务就会从“处理成功”改成“下达”状态。

     

    1.3. 修改操作和详情页面

      依据“下达”方式,url:http://localhost:8001/Task/1/change/就是跳到修改/详情界面查看和修改该任务详情数据。同样,我们还是采用渐进的原则的来推进这个功能的实现。

      首先,增加Task/urls.py 增加change url

    from django.urls import path,re_path
    
    
    from Task import views 
    
    urlpatterns = [
       
        path('', views.view_list,name='view_list'),
        re_path('^(?P<pk>d+)/start/$',views.start,name='start'),#
        re_path('^(?P<pk>d+)/change/$',views.change,name='change'),#
    
        
    ]

      标注②:change函数与start函数类似的写法,通过传入pk来获取需要修改的对象。

      然后,我们修改Task/views.py文件内容,增加change函数。

    ...
    
    def change(request,pk):
    
        obj = get_object_or_404(Task, pk=pk)
    return render(request,'Task/taskChange.html',{"task":obj})

      其次,我们采用模板页把task对象数据渲染到html上,这里我采用先加载显示出来。

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <div>{{task.TaskId }}</div>
        <div>{{task.TaskNum}}</div>
        <div>{{task.Source}}</div>
        <div>{{task.Target}}</div>
        <div>{{task.Barcode}}</div>
        <div>{{task.get_State_display}}</div>
        <div>{{task.get_Priority_display}}</div>
        <div>{{task.BeginDate}}</div>
        <div>{{task.EndDate}}</div>
        <div>{{task.job_set.count}}</div>
    </body>
    </html>

      运行结果

      最后,我们把模板页面修改成html input输入框,实现可以向后台post数据。本例我们假定未处理状态的任务可以修改源地址和目标地址信息。

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <h1>任务详情</h1>
        <div>{{task.TaskId }}</div>
        <div>{{task.TaskNum}}</div>
        {% if task.State == 1%} <!---->
        <form method="post">
            <input name="source" id="id_source" value="{{task.Source}}" />
            <input name="target" id="id_target" value="{{task.Target}}" />
            <input type="submit" value="提交">
        </form>
        {% else %}
        <div>{{task.Source}}</div>
        <div>{{task.Target}}</div>
        {% endif %}
    
        <div>{{task.get_State_display}}</div>
        <div>{{task.get_Priority_display}}</div>
        <div>{{task.BeginDate}}</div>
        <div>{{task.EndDate}}</div>
        <div>{{task.job_set.count}}</div>
    </body>
    </html>

      标注①:模板增加了 {% if %}判断,状态等于1 待处理状态的我们才能修改任务的源和目标地址,已经处理完成的任务就只能查看详情了,否则,job数据与task的数据逻辑就不一致了。

      企业开发过程中,确保数据逻辑的前后一致性是非常关键和重要的。

      运行效果:

     

     

    1.4. post数据更新到数据库

      现在修改数据后尝试点击提交按钮,通常情况下你会得到下面得错误提示页面,CSRF错误提示页面。

     

       Django针对CSRF得保护措施是在生成得每个表单中放置一个自动生成的令牌,通过这个令牌判断POST请求是否来自同一个网站。我们在<form></form>内放置一个{% csrf_token %} 即可,更多CSRF内容参考官网文档。

      运行结果

       现在报后台错误了,接下来我们实现views.py change函数。

    @atomic
    def change(request,pk):
        if request.method=='GET': #
            obj = get_object_or_404(Task, pk=pk)
            return render(request,'Task/taskChange.html',{"task":obj})
        elif request.method=='POST': #
            data={"Source":request.POST['source'],"Target":request.POST['target']}
            Task.objects.filter(pk=model.pk).update(**data)
        
            #重新刷新列表界面 #③
            co_path = request.path.split('/')
            new_path=co_path[0:2]
            new_path='/'.join(new_path)
            request.path = new_path
            return redirect(new_path)

      ①change函数get请求情况下返回查看详情页面;

      ②post请求情况下,使用post过来的参数更新对象属性;

      ③: 数据更新完成后重定向到列表页(也会重新加载列表数据,从而显示更新后的值);

      列表及时反映对象属性的变更是企业开发中常见的操作方式,否则用户就不知道这次修改和调整状态是否完成,不断的来回点击修改。 

      这里本人也讲述一下使用VS 2019常用到的一种调试方式就是在代码上打上断点,debug模式运行当程序执行到断点时会中断当前执行,便于开发人员验证过程的变量是否符合预期。

      好的,现在就在change函数内部打上断点,debug运行我们的工程,点击提交按钮在IDE里调试我们的代码,修正错误的写法。

     

       数据修改成功!

    1.5. 代码重复

      上面的代码中,笔者通过copy的方式把重定向到列表界面代码段在分别在startchange函数中重复了。遇到这种情况大多数开发人员尤其新手都会忽略,对于重复代码我们到底该怎么办?“事不过三”如果重复三次了一定得封装到一个函数里,这里我们直接把这段代码封装成__reloadTasksPage函数。

    ...  
            #重定向到列表界面 #③
            co_path = request.path.split('/')
            new_path=co_path[0:2]
            new_path='/'.join(new_path)
            request.path = new_path
            return redirect(new_path)

      重构后的代码

    ...
    
    @atomic
    def start(request,pk):
        #pk=request.GET.get('pk')
    
        obj = get_object_or_404(Task, pk=pk)#
    
        biz= TaskBiz()
        biz.task_start(obj) #
    
    return __reloadTasksPage(request)
    
    
    @atomic
    def change(request,pk):
        if request.method=='GET': #
            obj = get_object_or_404(Task, pk=pk)
            return render(request,'Task/taskChange.html',{"task":obj})
        elif request.method=='POST': #
            data={"Source":request.POST['source'],"Target":request.POST['target']}
            Task.objects.filter(pk=pk).update(**data)
        
            return __reloadTasksPage(request)
    
    
    def __reloadTasksPage(request):
            #重新刷新列表界面 #③
        co_path = request.path.split('/')
        new_path=co_path[0:2]
        new_path='/'.join(new_path)
        request.path = new_path
    return redirect(new_path)

      代码是不是简洁了好多,可能这个段代码重构会多花我们一点时间,长远来看这点时间事非常值得的,尤其后面如果调整到reloadTasksPage函数里的具体实现,大量散落和重复的代码是后期维护和扩展的噩梦!“敏捷”模式不提倡过度设计,但是如果“重复三次”,请重构你的代码。

    1.6. 小结

      本章我们详细的说明了如何实现客户端操作,读者可以自己试一试增加“处理”操作,实现对未处理状态的任务进行作业分解。客户端的操作会存在两种一种就是直接改变任务的状态,另外一种就是类似查看详情操作,这个种操作我们需要通过模板把数据加载处理,任务分解和下达之类的操作,更新完数据后重新加载数据即可。django对于这两种模式可以都是使用urlview组合来完成,这样在技术上两种模式就不存区别了,大大提高了开发效率。

  • 相关阅读:
    [iOS开发] 使用Jenkins自动打包并上传至蒲公英
    修改Jenkins的BUILD_NUMBER
    RabbitMQ on windows开启远程访问
    SpringMVC 表单复选框处理
    Spring文件上传配置
    ES6中Reflect 与 Proxy
    vuex中getter的用法
    Toast组建的实现
    link和@import的区别
    Vue组件之props选项
  • 原文地址:https://www.cnblogs.com/haozi0804/p/14657502.html
Copyright © 2011-2022 走看看