这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的“敏捷”模式。首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的执行情况列表。为了便于开发我们先设定一个目标url是http://localhost:8001/task/显示当前在执行的任务列表,同时,界面有操作按钮来执行针对任务的操作。
这里页面原型布局设计与Admin类似,如下图:
1.1. 配置url和view
为了便于对django的每个APP的url进行统一管理,我们先给Task添加一个urls.py的文件,task app发布的url将在这个文件里组织。
接下来在新增的urls.py文件里增加如下代码:
from django.urls import path from Task import views urlpatterns = [ path('', views.view_list,name='view_list'), ]
文件:Task/urls.py
同时,对应的在Task/views.py文件里增加函数view_list,代码如下:
from django.shortcuts import render from django.http import HttpResponse def view_list(request): return HttpResponse('hello world!')
现在我们在IndDemo/urls.py文件把发布Task/urls发布出来,代码如下:
from datetime import datetime from django.urls import path,re_path,include from django.contrib import admin from django.contrib.auth.views import LoginView, LogoutView from app import forms, views from Task import views as Task_views from Collector import views as Collector_views from Task import urls as task_urls urlpatterns = [ path('', views.home, name='home'), path('contact/', views.contact, name='contact'), path('about/', views.about, name='about'), path('login/', LoginView.as_view ( template_name='app/login.html', authentication_form=forms.BootstrapAuthenticationForm, extra_context= { 'title': 'Log in', 'year' : datetime.now().year, } ), name='login'), path('logout/', LogoutView.as_view(next_page='/'), name='logout'), path('admin/', admin.site.urls), path('admin/tank4C9/', Collector_views.tank4C9), path('getTank4C9Data/', Collector_views.getTank4C9Data), re_path('task/', include(task_urls)), #① ]
文件:IndDemo/urls.py
标注①:新的app urls发布方式,Task采用这种方式在工程中发布url后,后面Task/urls.py增加的url会自动发布,不用每次app增加url都需要去改工程的urls.py文件了。
现在我们工程项目Start server运行我们的工程,然后在浏览器键入http://localhost:8001/task/查看一下运行结果,会看到hello world! 显示在浏览器上,没错还是熟悉的hello world!。
1.2. 显示静态任务列表
接下来我们通过html显示任务列表数据,首先,采用静态拼字符串的方式来逐步推进编码的实现,直接反映一个静态的字符串数据。
from django.shortcuts import render from django.http import HttpResponse def view_list(request): html = "<html><head></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><td>1</td><td>100</td><td>101</td><td>05-01-01</td><td>101001001008</td>"\ + "<td>处理成功</td><td>正常</td><td>-</td><td>-</td><td>8</td><td>-</td></tr>"\ + "</table></body></html>" return HttpResponse(html)
查看运行结果
初步的效果就出来了,只是现在我们加载的不是数据库保存的数据,而是硬码再html文件里数据。
1.3. 动态任务列表
界面要显示动态的任务列表,就需要我们把数据从数据库表里抓出来后,采用model数据去拼这个返回html字符串变量,代码如下:
from django.shortcuts import render from django.http import HttpResponse def view_list(request): html = "<html><head></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>" tasks = Task.objects.all() for task in tasks: html = html + "<tr><td>"+str(task.TaskId )+ "</td><td>"+str(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>"+str(task.job_set.count())+"</td><td>-</td></tr>" html = html + "</table></body></html>" return HttpResponse(html)
运行结果
现在客户端UI能加载到数据库持久化的任务列表了,从上面的迭代编程过程我们演示是如何采用渐进的方式推进功能的开发,而每一步都能有通过运行的反馈!也就是每一个大目标是由一个一个成功的小目标累积而成的。
随着功能的增加我们会发现view_list里面的html脚本拼写会越来越复杂,再继续采用这种传统的拼接html脚本的方式效率只会越来越低,维护越来越麻烦。
1.4. 使用django模板重构
代码重构的定义是再功能不变的前提下,优化和改进代码的结构!现在我们采用django提供的模板来重构这个页面,从而把html标记语言与后台数据加载耦合分开,把业务逻辑与界面元数分开。
1.4.1. 静态模板
代码如下:
<!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> <tr> <td>1</td><td>100</td><td>101</td><td>05-01-01</td><td>101001001008</td><td>处理成功</td><td>正常</td><td>-</td><td>-</td><td>8</td><td>-</td> </tr> </table> </body> </html>
文件:Task/templates/tasks.html
修改view_list函数代码采用模板方式返回请求。
... def view_list(request): return render(request,'Task/tasks.html')
运行结果
1.4.2. 动态模板
接下来把这个模板重构到可以动态加载数据,更多关于django模板的的用法请参阅django的官方文档。
动态模板代码:
<!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>-</td> </tr> {%endfor%} </table> </body> </html>
修改view_list函数,动态加载任务列表。
... def view_list(request): tasks = Task.objects.all() return render(request,'Task/tasks.html',{"tasks":tasks})
运行结果
至此我们采用模板来替换再函数了拼html脚本的方式,你会发现view_list简洁多了不在包含html相关的内容,通过模板实现了数据加载与html解析过程的解耦合,从而大大的提高了代码的可读性和维护扩展能力。
过程我们仍然采用两步走的方式是进行重构,目的就是演示每一步都有通过运行的反馈,从而让我们理解采用模板方式(技术)是可行的。对于我们面对不确定的技术和编程新手来说,每一小步的正确推进,也是对掌握这个技术的肯定。
1.5. 小节
编程过程的每一个成功的一小步最终累积成一个完整的功能的编程模式和思路是我们面对不确定性(新技术、新框架、新业务、复杂业务)非常好的一种方式,通过每一小步的成功推进编码进程,同时及时获得反馈,运行错误反馈让我们及纠偏,运行正确继续推进。从而避免走到最后推倒重来的情况。笔者的编程生涯里,身边无数次发生的让人抓耳挠腮的实战案例。