前一章節介紹了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個問題,新增相對較為復雜,我們留給下一章節來重點講述。