zoukankan      html  css  js  c++  java
  • python工业互联网应用实战5—Django Admin 编辑界面和操作

    1.1. 编辑界面

      默认任务的编辑界面,对于model属性包含“choices”会自动显示下来列表供选择,“datetime”数据类型也默认提供时间选择组件,如下图:

     

      注意:“auto_now_add=True”的属性默认不会显示在编辑界面,外键字段会自动加载关联表数据,如上图操作员属性。

     1.1.1. 设置要显示的模型属性

      我们可以通过设置不显示操作员选项,代码如下:

    fields=('TaskNum','Source','Target',Barcode','State','Priority','BeginDate','EndDate')

      也可以采用exclude 属性设置排除不打算显示的模型属性。 

     exclude =('User',)

    1.1.2. 设置一行显示多个属性

      admin字段都是一个字段占一行若想两个字段放在同一行显示,设置代码如下

    fields=('TaskNum',('Source','Target'),'Barcode','State','Priority','BeginDate','EndDate')

    1.2. 编辑字段集合

      model字段比较多的可以采用fieldsets,该设置可以对字段分块,让编辑界面看起来比较整洁和统一,代码如下:

           fieldsets = (
            ("任务", {'fields': ['TaskNum', ('Source', 'Target'), 'Barcode','Priority',]}),
            ("摘要", {'fields':['State','BeginDate','EndDate']})
        )

    1.3. 设置只读字段

      我们使用admin编辑界面的时候,会有些字段是不希望用户直接编辑的,那么通过重写get_readonly_fields()函数来实现这一功能,代码如下: 

    def get_readonly_fields(self, request, obj=None):
            """  重写此函数,设置只读字段  """
            readonly_fields = ('State','BeginDate','EndDate')
            return readonly_fields

    1.4. 数据保存时自动登记操作员

      我们希望操作员是由系统自动登记的,不能人为修改,通过重写ModelAdminsave_model方法来实现。

     def save_model(self, request, obj, form, change):
            obj.User=request.user
            return super().save_model(request, obj, form, change)

    1.5. 任务下达操作

      现在我们增加一个“下达”操作来变更任务的状态,把“处理成功”状态的任务变成修改成“执行中”状态。

     # 增加自定义按钮
        actions = ['task_start_action',]
    
        def task_start_action(self, request, queryset):
            for obj in queryset:
                if obj.State==4:
                    obj.State=5
                    try:
                        obj.save()
                        self.message_user(request, str(queryset[0].TaskNum) + " 下达成功.")
                    except Exception:
                        self.message_user(request, str(queryset[0].TaskNum) + " 下达失败.")
                       
                else:
                    self.message_user(request, str(queryset[0].TaskNum) + " 下达失败.")
    
        task_start_action.short_description = '下达所选的' + ' 任务'

      到这里,我们通过自定义按钮实现了对model的操作,把任务的状态从“处理完成”变更成“执行中”,本文我们将遵照“敏捷编程”中从简的业务宗旨来推进我们的功能实现。并演示代码如何通过重构来保证业务的不断迭代变更。

      任务下达到“执行中”或“执行完成”后任务数据应该不允许再进行修改,需要把编辑页面变成数据浏览/查看页面。

    1.6. 执行中和完成的任务状态全部字段只读设置

      这里我们重构一下前面的get_readonly_fields函数,同时,通过数据库工具把其中1条数据状态设置成5,测试一下效果。

       def get_readonly_fields(self, request, obj=None):
            readonly_fields = ('State','BeginDate','EndDate','User')
            if hasattr(obj, 'State'):
                if obj.State in(5,99):
                    readonly_fields = ('TaskNum', 'Source', 'Target', 'Barcode','State','Priority','BeginDate','EndDate','User')
    
            return readonly_fields 

    1.7. 重构任务下达操作函数

      1.6实现任务“下达”自定义按钮功能,操作起来需要先选择需要下达的行,然后再选择“下达所选的 任务”,最后点击执行操起起来过于繁琐,多行选择操作还好,单行选择操作就极度不符合用户的使用习惯。

      通过重构任务下达函数,支持列表行操作“下达”功能,这样对于单行操作来说用户通过直接点击行的“操作”列下的“下达”链接即可以直接对数据行进行“下达”操作,提供人机界面的易用性。 

    1.7.1. 增加列操作功能

      首先,我们增加列表操作功能列和行下达操作链接,代码和实现效果如下:

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
        def task_operate(self,obj):
            dest = 'taskStart/{}'.format(obj.pk)
            title = '下达'
            return format_html('<a href="{}">{}</a>'.format(dest, title))
    
        task_operate.short_description = '操作'

    1.7.2. 重构task_start_action函数,增加业务功能函数task_start()

      我们task_start()函数把model的业务逻辑代码进行封装,通过这个函数的重用来保证,无论是通过action按钮还是功能列下达的业务逻辑是一致的。

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
       # 增加自定义按钮
        actions = ['task_start_action',]
    
        def task_start_action(self, request, queryset):
            for obj in queryset:
                result=self.task_start(obj)
                if result:
                    self.message_user(request, str(obj.TaskNum) + " 下达成功.")
                else:
                    self.message_user(request, str(obj.TaskNum) + " 下达失败.")
    
        task_start_action.short_description = '下达所选的' + ' 任务'
    
    
        def task_start(self,obj):
            success=False
            if obj.State==4:
                obj.State=5
                try:
                    obj.save()
                    success = True
                except Exception:
                    success = False               
            return  success 

      代码重构要点之一就是先确保满足原有业务功能的前提下,调整代码的结构,上面的代码增加的task_start并没有改变原先的业务逻辑,所以通过原来的action仍然能够正常下达选中的任务。

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
        def task_operate(self,obj):
            url = '{}/taskStart/'.format(obj.pk)
            oprName = '下达'
            return format_html('<a href="{}">{}</a>'.format(url, oprName))
    
        task_operate.short_description = '操作'  

      接下来我们先增加操作列的下达链接操作,刷新列表页我们就能看到操作按钮链接了。然后,我们依据修改的url规则来构建taskStart url “/admin/Task/task/1/taskStart /”用来响应点击下达链接响应事件,代码如下:

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
        def task_operate(self,obj):
            url = '{}/taskStart/'.format(obj.pk)
            oprName = '下达'
            return format_html('<a href="{}">{}</a>'.format(url, oprName))
    
        task_operate.short_description = '操作'
        #task_operate.allow_tags = True
    
        def get_urls(self):
            """添加一个url,指向任务下达功能的函数taskStart()"""
            from django.conf.urls import url
            urls = [
                re_path('(?P<pk>d+)/taskStart/',
                    self.admin_site.admin_view(self.task_start_view),
                    name='task_start_view'),
            ]
            return urls + super(TaskAdmin, self).get_urls()
    
        def task_start_view(self, request, *args, **kwargs):
            
            obj = get_object_or_404(Task, pk=kwargs['pk'])
            self.task_start(obj)
    
            #数据更新成功后,重新刷新列表界面
            co_path = request.path.split('/')
            new_path=co_path[0:4]
            new_path='/'.join(new_path)
            return redirect(new_path) 

      现在我们在列表上点击“下达”链接,测试下达操作效果,效果如下图:

      

    1.8. 模拟异常初窥事务

      本章节我们演示了通过“下达”事件修改对应model的状态值,从而实现“任务”业务从一个状态到另一个状态的转换,现在我们通过一个模拟异常来演示也是事务的完整性问题,在一个业务操作里相关的业务数据变化要保持一致性。当出现异常需要回滚时,必须回滚所有涉及的对象(表)数据。

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
        def task_start_view(self, request, *args, **kwargs):
            
            obj = get_object_or_404(Task, pk=kwargs['pk'])
            self.task_start(obj)
            raise Exception('模拟抛出异常!')       
            #重新刷新列表界面
            co_path = request.path.split('/')
            new_path=co_path[0:4]
            new_path='/'.join(new_path)
            request.path = new_path
            return redirect(new_path)

      上面的代码我们模拟调用self.task_start(obj)后,模拟出现异常,出现异常后应该需要回滚obj的状态,从而确保事务的一致性,尤其操作涉及到多个对象时,避免出现事务不一致的情况。由于现在代码没有事务约束机制,所以异常抛出后我们会发现obj的状态还是变更成“执行中”了。 

     

     

      现在增加事务约束来保证事务的一致性,再测试一遍发现变更的状态回滚回去了。

    #Task模型的管理器
    class TaskAdmin(admin.ModelAdmin):
    ...
    
        from django.db.transaction import atomic
        @atomic
        def task_start_view(self, request, *args, **kwargs):
            
            obj = get_object_or_404(Task, pk=kwargs['pk'])
            self.task_start(obj)
            raise Exception('模拟抛出异常!')       
            #重新刷新列表界面
            co_path = request.path.split('/')
            new_path=co_path[0:4]
            new_path='/'.join(new_path)
            request.path = new_path
            return redirect(new_path) 

    1.9. 小结

      本章节我们主要介绍了admin后台管理的编辑界面设置,通过两个章节完成了admin的初步介绍和设置,后面我们会根据内容的穿插admin的其它一些配置项。本章我们还简要的模拟演示了业务事务的一致性问题,当某一个业务操作过程中出现异常时,需要回滚当前的所有操作,事务的部分完成在企业的开发中是不能被允许的!

      通过django admin我们快速的构建了一个任务的管理系统原型,下一章节我们将进一步增加功能讲述如何分解任务到作业(子任务),并通过代码重构改进代码的组织结构。

  • 相关阅读:
    JS和C# 里的闭包及闭包在事件中的使用
    ***项目开发记录
    七牛云存储之应用视频上传系统开心得
    二维码及二维码接合短URL的应用
    EF批量添加,删除,修改的扩展
    ngTemplateOutlet递归的问题
    每日新知2019-06-03
    Spring boot初始
    纯前端播放本地音乐
    macbook 安装任意来源
  • 原文地址:https://www.cnblogs.com/haozi0804/p/14366480.html
Copyright © 2011-2022 走看看