根據需求定義「任務」是一個完整的業務搬運流程,整個流程涉及到多個機構(設備)分別動做執行多個步驟,因此依據前面的模型設計,須要把任務分解到多個連續的子任務(做業),將來經過順序串聯下達執行的方式來分步驟的完成任務的執行。數據庫
一樣,依據需求咱們先來作幾個倉庫的規劃設計,101位置是AGV的入庫起始站臺,102是提高機門口的入庫工位,104是提高機1樓轎廂工位,同理504是提高機在5樓的轎廂工位。左邊是5樓的貨位區編碼規則,完整好的貨位號加上樓層編碼05-01-01表示五樓的01-01貨位,以下圖:編程
有了圖上的基本倉庫規劃設計,咱們才能把一個任務依據設計進行分解,例如:任務編碼100的搬運任務是把貨物從101 入庫工位搬運到05-01-01貨位存放。函數
設計約定:編碼
① 10二、502爲進提高機工位,10三、503爲出提高機工位,出和入的工位分開來解決任務衝突的問題(固然也能夠先規劃一個工位,隨着程序迭代改進)。atom
② 提高機控制邏輯與電梯相似,到達指定樓層後會自動開門。spa
③ 電梯只有關上廊門才能提高/降低。設計
這樣根據約定(前置條件)如今咱們針對這個任務逐步分解成如下子任務(做業)以下表,對照早期的需求會發現有增長做業,實際項目中也是如此,早期的需求定義到實際編碼的時候,須要根據實際的設備接口協議,規定等調整早期的需求定義。code
序號orm |
做業描述blog |
執行設備 |
1 |
調度AGV從101站臺搬運托盤到102站臺 |
1樓AGV |
2 |
調度提高機到1樓並打開門 |
提高機 |
3 |
調度AGV從102工位搬運到104工位並卸貨 |
1樓AGV |
4 |
調度空AGV從104工位到103工位 |
1樓AGV |
5 |
調度提高機關門 |
提高機 |
6 |
調度提高機1樓提高到5樓並開門 |
提高機 |
7 |
調度空AGV到504工位並載貨 |
5樓AGV |
8 |
調度AGV從504工位到503工位 |
5樓AGV |
9 |
調度提高機關門 |
提高機 |
10 |
調度AGV從503工位搬運到05-01-01貨位並卸貨 |
5樓AGV |
上面的分解比需求表增長了兩個子任務「調度空AGV從104工位到102工位」和「調度AGV從504工位到502工位」,是與實際的AGV設備對接通訊協議後增長的,AGV小車的控制系統不能識別「調度AGV從提高機1樓門口工位到提高機並卸貨,返回提高機門口工位」需求裏「返回」提高機門口工位。依據設備的接口邏輯,只能把這個步驟再分解成兩個步驟來執行。
上述分解提供一個簡化分解的模型和思路,實際項目可能更爲複雜或簡單。
咱們在後臺任務管理裏添加任務編碼100、源地址10一、目標地址05-01-01的任務,以下圖:
同時admin.py裏增長新增任務默認狀態設置爲未處理的代碼,咱們經過pk值是否爲None來判斷model是不是新增仍是修改。
#Task模型的管理器 class TaskAdmin(admin.ModelAdmin): ... def save_model(self, request, obj, form, change): #新增任務默認狀態設置爲 未處理 if obj.pk==None: obj.State=1 obj.User=request.user return super().save_model(request, obj, form, change)
接下來,咱們演示如何依據上面的分解邏輯用代碼來實現把任務分解成子任務並保存到Job對應的表裏,同時,把任務的狀態從「未處理」更新到「處理完成」狀態。這裏須要注意的就是任務的分解和狀態變動必須在一個事務裏完成,系統不能存在任務狀態已經變動處處理完成,可是沒有對應的做業,也不能存在已有對應的做業任務狀態仍然是未處理狀態的情形,不然就會形成系統業務上的混亂,前面章節提到的事務應用就很是重要!
#Task模型的管理器 class TaskAdmin(admin.ModelAdmin): ... @atomic def task_decompose_action(self, request, queryset): for obj in queryset: #只處理狀態等於未處理的任務 if obj.State==1: result=self.task_decompose(request,obj) if result: self.message_user(request, str(obj.TaskNum) + " 處理成功.") else: self.message_user(request, str(obj.TaskNum) + " 處理成功.") task_decompose_action.short_description = '處理所選的' + ' 任務' def task_decompose(self,request,obj): success=True try: job1=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":1,"Source":obj.Source,"Target":'102',"Executor":"AGV01","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job1.save() job2=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":2,"Source":None,"Target":'1',"Executor":"ELEVATOR","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job2.save() job3=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":3,"Source":"102","Target":'104',"Executor":"AGV01","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job3.save() job4=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":4,"Source":'104',"Target":'103',"Executor":"AGV01","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job4.save() job5=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":5,"Source":'1',"Target":'5',"Executor":"ELEVATOR","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job5.save() job6=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":6,"Source":'504',"Target":'503',"Executor":"AGV05","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job6.save() job7=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":7,"Source":'5',"Target":None,"Executor":"ELEVATOR","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job7.save() job8=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":8,"Source":'503',"Target":'05-01-01',"Executor":"AGV05","State":1,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job8.save() #子任務分解完成,並提交數據庫 #更新任務的狀態到「處理完成」 obj.State=5 obj.save() except Exception: success = False return success
執行效果以下圖:
任務分解完成後,列表除了顯示狀態變化以外,可以查看做業的分解數量,爲此在Task Admin裏增長job_count函數用來顯示做業數量。
#Task模型的管理器 class TaskAdmin(admin.ModelAdmin): #listdisplay設置要顯示在列表中的字段(TaskId字段是Django模型的主鍵) list_display = ('TaskId','TaskNum', 'Source', 'Target', 'Barcode','State','PriorityColor','BeginDate','EndDate','job_count','task_operate',) ... def job_count(self, obj): return obj.job_set.count() job_count.short_description = '做業數量'
Job模型外鍵管理Task模型,我就能夠採用TabularInline的方式來顯示任務的做業信息,經過編輯界面直接查看對應任務的Job列表。
class JobInline(admin.TabularInline): model = Job fields = ('TaskNum','OrderNo','Source', 'Target','Executor','State','BeginDate','EndDate',) extra = 0 #默認全部條目 # 只讀的字段 readonly_fields = ('TaskNum','OrderNo','Source', 'Target','Executor','State','BeginDate','EndDate',) def has_delete_permission(self, request, obj=None): return False #不容許刪除 def has_add_permission(self, request, obj=None): return False #不容許添加 #Task模型的管理器 class TaskAdmin(admin.ModelAdmin): #listdisplay設置要顯示在列表中的字段(TaskId字段是Django模型的主鍵) list_display = ('TaskId','TaskNum', 'Source', 'Target', 'Barcode','State','PriorityColor','BeginDate','EndDate','job_count','task_operate',) inlines=[JobInline] fieldsets = (("任務", {'fields': ['TaskNum', ('Source', 'Target'), 'Barcode','Priority','State','BeginDate','EndDate','User']}),)
任務的狀態賦值和變動咱們採用了直接obj.State=1或obj.State=5的直接賦值數字的方式,這個就是程序的mogic number它們有特殊的含義,編程人員得知道這個數字對應的含義,當狀態變多時間拉長,編程人員就得去回憶或來回查看數字對應的狀態。好的編程習慣就是用常量來代替魔法數字。重構models.py裏的Task和Job代碼用常量替換mogic number.
class Task(models.Model): STATE_NEW =1 STATE_PROCESSED=4 STATE_RUNNING=5 STATE_COMPLETED=99 STATE_CANCEL=-1 TASK_STATE=((STATE_NEW,u'未處理'),(STATE_PROCESSED,u'處理成功'),(STATE_RUNNING,u'執行中'),(STATE_COMPLETED,u'完成'),(STATE_CANCEL,u'已取消')) TaskId = models.AutoField(u'ID',primary_key=True, db_column='task_id') TaskNum = models.IntegerField(u'任務號', null=False, db_column='task_num') Source = models.CharField(u'源地址', null=False, max_length=50, db_column='source') Target = models.CharField(u'目標地址', null=False, max_length=50, db_column='target') Barcode = models.CharField(u'容器條碼', null=False, max_length=50, db_column='barcode') State = models.IntegerField(u'狀態', choices=TASK_STATE, null=False, db_column='state') Priority = models.IntegerField(u'優先級', choices=PRIORITY, null=True, db_column='priority') BeginDate = models.DateTimeField(u'開始時間',null=True, db_column='begin_date') EndDate = models.DateTimeField(u'結束時間',null=True, db_column='end_date') SystemDate = models.DateTimeField(u'系統時間', null=False, auto_now_add=True, db_column='system_date') User = models.ForeignKey(User, verbose_name="操做員",null=True, on_delete=models.CASCADE,db_column='user_id') class Meta: db_table = 'task_task' ordering = ['-Priority','TaskId'] verbose_name = verbose_name_plural = "任務" ... class Job(models.Model): STATE_NEW =1 STATE_START=2 STATE_COMPLETED=99 STATE_CANCEL=-1 JOB_STATE=((STATE_NEW,u'新做業'),(STATE_START,u'下達執行'), (STATE_COMPLETED,u'完成'),(STATE_CANCEL,u'已取消'))
凡有魔法數字的地方都儘可能替換成能夠閱讀的常量,採用中式英語都是能夠推薦的方式:)。
class TaskBiz(object): """description of class""" def task_start(self,obj): success=False if obj.State==Task.STATE_PROCESSED: obj.State=Task.STATE_RUNNING try: obj.save() success = True except Exception: success = False return success ... def task_decompose(self,request,obj): success=True try: job1=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":1,"Source":obj.Source,"Target":'102',"Executor":"AGV01","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job1.save() job2=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":2,"Source":None,"Target":'1',"Executor":"ELEVATOR","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job2.save() job3=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":3,"Source":"102","Target":'104',"Executor":"AGV01","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job3.save() job4=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":4,"Source":'104',"Target":'103',"Executor":"AGV01","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job4.save() job5=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":5,"Source":'1',"Target":'5',"Executor":"ELEVATOR","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job5.save() job6=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":6,"Source":'504',"Target":'503',"Executor":"AGV05","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job6.save() job7=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":7,"Source":'5',"Target":None,"Executor":"ELEVATOR","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job7.save() job8=Job(**{"Task":obj,"TaskNum":obj.TaskNum,"OrderNo":8,"Source":'503',"Target":'05-01-01',"Executor":"AGV05","State":Job.STATE_NEW,\ "Priority":obj.Priority,"Barcode":obj.Barcode,"User":request.user,}) job8.save() #子任務分解完成,並提交數據庫 #更新任務的狀態到「處理完成」 obj.State=Task.STATE_PROCESSED obj.save() except Exception: success = False return success
本章節咱們講述瞭如何經過admin.py來快速的完成頁面功能的構建,並經過自定義action快速的實現了任務分解功能,並根據業務進展也逐步的完善了查看頁面之內聯表的方式顯示做業詳情。隨着業務功能的增長admin.py的代碼逐步增多和變得複雜,下一章咱們演示如何經過功能內聚和重構代碼,增長代碼可讀性和可維護性。