Django自定义Action

上次安装了Django之后,自己摸索玩了一段时间,没想到最近因为需要接下了一个使用Django的工作,感觉个人真的是按需折腾啊。

接手的工作中,Django的框架大致搭好,在测试中发现,admin管理界面本身挺方便的,但是默认的界面总感觉缺点什么,首先看图:

模型原始的管理界面如上,模型代码 model.py:

 1 # coding:utf-8
 2 from django.db import models
 3 from blast_service.models import DiskInfo
 4 # Create your models here.
 5 class GenomicsFileInfo(models.Model):
 6     COMPUTE_STATE = (
 7          (0, 'computing'),
 8          (1, 'computed'),
 9          (2, 'idle'),
10     )
11     ACHIVE_STATUS = (
12         (0, 'Not archive'),
13         (1, 'Archive failed'),
14         (2, 'Archive success'),
15         (3, 'Ignore'),
16         (4, 'Archiving')
17     )
18 
19     SEND_STATUS = (
20         (0, 'idle'),
21         (1, 'sended'),
22     )
23     userid = models.CharField(max_length=32,blank=True)
24     cluster_account = models.CharField(max_length=32)
25     filename = models.CharField(max_length=100)
26     md5 = models.CharField(max_length=32, blank=True)
27     file_path = models.CharField(max_length=500)
28     updatetime = models.DateTimeField(auto_now_add=True)
29     diskinfo = models.ForeignKey(DiskInfo, on_delete=models.CASCADE,)
30     size = models.BigIntegerField(blank=True)
31     compute_state = models.IntegerField(choices=COMPUTE_STATE, default=2)
32     achive_status = models.IntegerField(choices=ACHIVE_STATUS, default=0)
33     achive_path = models.CharField(max_length=500, blank=True)
34     is_deleted = models.BooleanField(default=False, verbose_name=u'delete tag')
35     class Meta:
36         unique_together = ('userid', 'file_path','filename')
37         db_table = 'GenomicsFileInfo'
38     def __unicode__(self):
39         return self.file_path
View Code

admin.py是原始未改动:

1 from django.contrib import admin
2 
3 # Register your models here.
4 from models import GenomicsFileInfo
5 
6 admin.site.register(GenomicsFileInfo)
View Code

本以为这样也挺好的,随着测试的进行,数据库中保存的记录也越多,对接做前端系统的同事某一天问我:“我上传了一个文件,一直没有计算完成,我在管理界面中找不到它啊,为啥没找到你们的搜索栏呢?”我一愣,赶紧上去一看,对啊,我没有搜索栏我咋找数据库的记录呢?

网上一顿搜索,原来admin有很多很方便的组件都没有用上,我一想,现在管理界面上只显示了文件路径,我将文件名也显示上来,不就可以直接 control+f 来搜索了。

修改admin.py:

1 from django.contrib import admin
2 
3 # Register your models here.
4 from models import GenomicsFileInfo
5 
6 class GenomicsFileInfoAdmin(admin.ModelAdmin):  # 添加一个对模型的管理类
7     list_display = ('file_path','filename')  #添加一个显示的组件,显示文件路径和文件名
8 
9 admin.site.register(GenomicsFileInfo, GenomicsFileInfoAdmin)  #将管理类注册到admin中
View Code

修改完成后界面如下:

确实将文件名也显示出来了,我一想,我还有计算的状态,归档的状态等,都可以列出来呢,那就一起吧,修改admin.py:

1 from django.contrib import admin
2 
3 # Register your models here.
4 from models import GenomicsFileInfo
5 
6 class GenomicsFileInfoAdmin(admin.ModelAdmin):
7     list_display = ('file_path','filename','cluster_account','compute_state','achive_status','is_deleted')  #需要展示在页面上的字段都可以列在这里
8 
9 admin.site.register(GenomicsFileInfo, GenomicsFileInfoAdmin)
View Code

效果如下:

随之而来的问题是,control+f 在少量记录是还可以使用,多条记录分页之后,完全不可行啊,而且我只想显示某个文件名的记录,或者某种状态的记录的话,这完全就是废的。因此,我们必须用上admin的search组件和filter组件。

1. 其中search就是搜索栏,由于Django中的模型就是数据库中的表,所以搜索可以类似于数据库中的 'select '语句,这个组件指定搜索的字段,类似于sql中 where colname like '%搜索的内容%';

2. filter组件就是过滤,指定字段,其效果相当于sql中的 where colname = '某个内容',这个组件比较适用于值域确定的字段。

来看一起修改后但admin.py:

 1 from django.contrib import admin
 2 
 3 # Register your models here.
 4 from models import GenomicsFileInfo
 5 
 6 class GenomicsFileInfoAdmin(admin.ModelAdmin):
 7     list_display = ('file_path','filename','cluster_account','compute_state','achive_status','is_deleted')
 8     search_fields = ('file_path','filename','md5','userid')  #search组件,指定输入搜索内容后,只在文件路径,文件名,md5和用户id这几个字段搜索
 9     list_filter = ('compute_state','achive_status','is_deleted')  #filter组件,由于我但表中这个几个字段有确定的值域,所以filter就列这几个字段
10 
11 admin.site.register(GenomicsFileInfo, GenomicsFileInfoAdmin)
View Code

这样看起来界面完整多了,可又出现了麻烦的事,我搜索(过滤)到了想要的记录,然后希望批量修改他们的状态或者字段值,总不能一条一条记录点进去改吧?如果10000条记录,那我一天的工作就交代了(苦笑)。

其实Django的admin管理工具中只有一个默认的操作,就是批量删除选中的记录(见第一张图☝️的Action部分),所以我们需要自定义(手动)添加我们需要的Action。

假设我们的需求是,将选中的记录中compute_state修改为computed(1),这种需求,其实网上很多篇博文都有写到,直接上代码,admin.py:

 1 from django.contrib import admin
 2 
 3 # Register your models here.
 4 from models import GenomicsFileInfo
 5 
 6 compute_state = {0:'computing', 1:'computed', 2:'idle'}  #计算状态的字典
 7 
 8 def change2computed(modeladmin, request, queryset):  #新建一个批量操作的函数,其中有三个参数:
 9 #第一个参数是模型管理类,第二个request是请求,第三个queryset表示你选中的所有记录,这个函数里面会处理所有选中的queryset,所以要在操作之前用搜索或者过滤来选出需要修改的记录
10     queryset.update(compute_state=1)  #改变数据库表中,选中的记录的状态
11 change2computed.short_description = 'Change compute state to computed'  #这个是在界面显示的描述信息
12 
13 
14 class GenomicsFileInfoAdmin(admin.ModelAdmin):
15     list_display = ('file_path','filename','cluster_account','compute_state','achive_status','is_deleted')
16     search_fields = ('file_path','filename','md5','userid')
17     list_filter = ('compute_state','achive_status','is_deleted')
18     actions = [change2computed,]  #添加actions的列表,表示要在页面上显示的操作
19 
20 admin.site.register(GenomicsFileInfo, GenomicsFileInfoAdmin)
View Code

 效果如下图:

在Action中除了默认的操作,还多了一个我们自定义的操作。这种自定义的方式是最简单的方式,随之而来的问题是,如果我操作的状态有 computing,computed,idle,根据归档状态又有5种,那我就要写8个函数,再添加到actions中,而且每次新加之后又要重新启动,就会很麻烦。而Django的管理类有一个get_action的函数,可以根据规则获取actions,网上也有少许资料,我直接用代码解释,修改admin.py:

 1 import collections  #导入模块后续要用到
 2 
 3 from django.contrib import admin
 4 # Register your models here.
 5 from models import GenomicsFileInfo
 6 
 7 ##字段的状态
 8 compute_state = {0:'computing', 1:'computed', 2:'idle'}  
 9 achive_status = {0:'Not archive', 1:'Archive failed', 2:'Archive success', 3:'Ignore', 4:'Arching'}
10 
11 ## 将刚刚简单的函数注释掉
12 '''
13 def change2computed(modeladmin, request, queryset):
14     queryset.update(compute_state=1)
15 change2computed.short_description = 'Change compute state to computed'
16 '''
17 
18 ## 下面👇新建一个闭包
19 def _change_state(state, typename):  ## 新建一个函数,参数是需要修改成的状态值,和指定字段的标记符
20     if typename == 'compute':  # 如果标记符是compute
21         fileds_name = 'compute_state'  #那么需要修改的字段是 compete_state
22         show = compute_state[state]   #这个主要用作显示名称
23     elif typename == 'archive':  # 如果标记符是 archive
24         fileds_name = 'archive_status'  #那么需要修改的字段是 archive_status
25         show = achive_status[state]
26     else:
27         return None #其他的返回None
28 
29     def set_selected(modeladmin,request, queryset):  ##主要修改数据库的函数,根据之前的字段和值进行修改,和刚刚简单的那个函数功能一致
30         kwargs = {}
31         kwargs[fileds_name] = state
32         return queryset.update(**kwargs)
33 
34     set_selected.short_description = 'Change selected to {0}'.format(show)  # 管理界面显示的名称
35     set_selected.__name__ = 'change_to_{0}'.format(show)  # 同一个字段可以有多种状态进行修改,每种状态赋一个不同的函数名用以指定不同的操作
36     return set_selected  ##返回修改数据库的函数
37 
38 
39 class GenomicsFileInfoAdmin(admin.ModelAdmin):
40     list_display = ('file_path','filename','cluster_account','compute_state','achive_status','is_deleted')
41     search_fields = ('file_path','filename','md5','userid')
42     list_filter = ('compute_state','achive_status','is_deleted')
43     #actions = [change2computed,]  #将刚刚的语句注释掉
44     
45     def get_actions(self, request):  #使用get_actions函数来自动获取actions
46         action = super(GenomicsFileInfoAdmin, self).get_actions(request)  #这一步主要是要保留原有的批量删除操作和其他已经定义过的操作
47         fns = [_change_state(i, 'compute') for i in compute_state]  #调用闭包获取到所有操作的函数名
48         fns += [_change_state(i, 'archive') for i in achive_status]
49         actions = [ self.get_action(fn) for fn in fns ]  #使用管理类的函数来获取每个操作
50         ## 下面这一步很关键,actions表面是一个列表,但是实际上是一个字典,每个函数名都要对应上其功能函数,函数名以及对应的描述,所以最后要将其转换为字典形式
51         actions = collections.OrderedDict( 
52              (name, (func, name, desc))
53             for func, name, desc in actions
54         )
55 
56         actions = dict(action, **actions)  ##这一步是合并字典,是将最开始获取到的默认操作添加到最终的actions中
57         return actions  # 返回最终的actions
58 
59 
60 admin.site.register(GenomicsFileInfo, GenomicsFileInfoAdmin)
View Code

最终的显示效果如下:

 

有我们自定义的操作与其默认的操作。使用get_actions函数的另一个好处是,当我修改admin.py代码,在其函数中添加新的操作时,不用重启Django,之需要刷新页面即可。

OK,最终的效果如上,如若后续有修改会继续更博~

posted @ 2019-01-31 15:16  Luxiaoxiaohui  阅读(3334)  评论(0编辑  收藏  举报