1. 程式人生 > >django自定義Admin actions

django自定義Admin actions

通常情況下,admin的工作模式是“選中目標,然後修改目標”,但在同時修改大量目標的時候,這種模式就變得重複、繁瑣。

為此,admin提供了自定義功能函式actions的手段,可以批量對資料進行修改。admin內建了一個批量刪除物件的操作,如下圖所示:

19.png-40.6kB

下面以一個新聞應用的文章模型為例,介紹一個批量更新的自定義actions,它將選擇的文章由“草稿”狀態更新為“釋出”狀態:

首先是模型的程式碼:

from django.db import models

STATUS_CHOICES = ( ('d', 'Draft'), ('p', 'Published'), ('w', 'Withdrawn'), ) class Article(models.Model): title = models.CharField(max_length=100) body = models.TextField() status = models.CharField(max_length=1, choices=STATUS_CHOICES) def __str__(self): # __unicode__ on Python 2 return self.title 

一、編寫action

action必須攜帶三個引數:

  • 當前的ModelAdmin
  • 當前的HttpRequest物件(即request)
  • 被選擇的物件(即QuerySet)

在應用中的admin.py檔案中寫入:

def make_published(modeladmin, request, queryset): queryset.update(status='p') 

注意:這裡我們作為例子,簡單地使用了queryset自帶的update()方法,它能批量操作。但在多數情況下,你要自己遍歷queryset的每個元素,並編寫具體的操作。也就是:

for obj in queryset:
    do_something_with(obj)

還可以設定一個簡單易懂的簡短描述(可以使用中文),用於代替生硬的函式名:

def make_published(modeladmin, request, queryset): queryset.update(status='p') # 注意縮排,下面這句不在函式體內。 make_published.short_description = "Mark selected stories as published" 

二、將自定義action新增到對應的ModelAdmin中

關鍵是其中的actions = [make_published]這句。

from django.contrib import admin
from myapp.models import Article def make_published(modeladmin, request, queryset): queryset.update(status='p') make_published.short_description = "Mark selected stories as published" class ArticleAdmin(admin.ModelAdmin): list_display = ['title', 'status'] ordering = ['title'] actions = [make_published] admin.site.register(Article, ArticleAdmin) 

然後,頁面看起來是下面的樣子(注意下拉框):

20.png-61.5kB

處理錯誤

這其中,如果你能夠預知在自定義的操作中可能產生的錯誤,請處理該錯誤,並通過django.contrib.admin.ModelAdmin.message_user()以友好的方式給予使用者提示資訊。

三、將action定義為ModelAdmin的方法

上面的make_published看起來已經不錯了,但是我們一般會將它作為ModelAdmin的方法來使用。下面我們把它移到ArticleAdmin類中:

class ArticleAdmin(admin.ModelAdmin): ... actions = ['make_published'] # 請注意這裡改成字串引用了 # 第一個引數變為self def make_published(self, request, queryset): queryset.update(status='p') make_published.short_description = "Mark selected stories as published" 

這樣做的好處是自定義方法可以直接訪問類本身。例如下面使用self引用,為方法新增提示資訊的功能:

class ArticleAdmin(admin.ModelAdmin): ... def make_published(self, request, queryset): rows_updated = queryset.update(status='p') if rows_updated == 1: message_bit = "1 story was" else: message_bit = "%s stories were" % rows_updated self.message_user(request, "%s successfully marked as published." % message_bit) 

回到瀏覽器,再試試,你會看到如下圖所示(注意頂部的綠色提示行):

21.png-68.8kB

四、跳轉到中間頁面

預設情況下,執行完actions後,瀏覽器會返回先前的修改列表頁面。但有時候,一些複雜的action需要返回中間頁面,例如內建的刪除方法,在執行刪除動作之前,會彈出一個刪除確認頁面。

要實現這個功能,只需要在action方法中返回一個HttpResponse(或它的子類)。 例如下面是一個利用Django內建的序列化函式將一個物件儲存為json格式的範例:

from django.http import HttpResponse
from django.core import serializers def export_as_json(modeladmin, request, queryset): response = HttpResponse(content_type="application/json") serializers.serialize("json", queryset, stream=response) return response 

多數情況下,我們會使用HttpResponseRedirect跳轉到一箇中間頁面,並在GET方法的url中攜帶別選擇的物件作為引數傳遞過去,然後在這個新的檢視中接收這個引數,並編寫具體的更加複雜的業務邏輯,如下面的程式碼所示:

from django.contrib import admin
from django.contrib.contenttypes.models import ContentType from django.http import HttpResponseRedirect def export_selected_objects(modeladmin, request, queryset): # 獲得被打鉤的checkbox對應的物件 selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) # 獲取對應的模型 ct = ContentType.objects.get_for_model(queryset.model) # 構造訪問的url,使用GET方法,跳轉到相應的頁面 return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected))) 

具體的業務views這裡沒有給出,作為練習,留給大家。

五、編寫可用於整個admin站點的action

前面建立的actions智慧應用於繫結的模型。實際上有時候,我們還需要可以對admin站點內所有模型都有效的acitons。上面寫的export_selected_objects函式可以是一個很好的例子。要實現這一功能,你需要使用內建的AdminSite.add_action方法:

AdminSite.add_action(action, name=None)[source]

from django.contrib import admin

admin.site.add_action(export_selected_objects) 

六、禁用acitons

有時候,對於某些actions,我們想全域性禁用或者區域性禁用它。需要使用AdminSite.disable_action(name)方法。

  • 禁用全站級別的acitons:

例如,禁用內建的刪除方法:

admin.site.disable_action('delete_selected')
  • 全站禁用,但個別可用:在ModelAdmin.actions中顯式地引用。

例如:

# 全站禁用刪除功能
admin.site.disable_action('delete_selected') # 這個老老實實的被禁了 class SomeModelAdmin(admin.ModelAdmin): actions = ['some_other_action'] ... # 這個宣告:我還要用 class AnotherModelAdmin(admin.ModelAdmin): actions = ['delete_selected', 'a_third_action'] ... 
  • 在指定模型中禁用所有actions:設定ModelAdmin.actions為None。(這會連帶全域性actions一起禁用了。)
    class MyModelAdmin(admin.ModelAdmin):
        actions = None 
  • 根據條件自動啟用或禁用:

還可以根據條件自動選擇性的啟動或禁用某些acitons,你只需要改寫ModelAdmin.get_actions()方法。

該方法將返回一個包含actions的字典。字典的鍵是aciton的名字(也就是前面的'delete_selected', 'a_third_action'之類),值是一個元組,包含(函式、名字、別名)

例如,允許使用者名稱以“J”開頭的使用者批量刪除物件,但其它使用者不行:

class MyModelAdmin(admin.ModelAdmin): ... def get_actions(self, request): actions = super(MyModelAdmin, self).get_actions(request) if request.user.username[0].upper() != 'J': if 'delete_selected' in actions: del actions['delete_selected'] return actions