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,最終的效果如上,如若后續有修改會繼續更博~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM