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組合來完成,這樣在技術上兩種模式就不存區別了,大大提高了開發效率。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM