鍍金池/ 教程/ Python/ 管理操作
點擊劫持保護
安全問題歸檔
Model 類參考
將遺留數(shù)據(jù)庫整合到Django
關(guān)聯(lián)對象參考
內(nèi)建基于類的視圖的API
聚合
Django 中的用戶認證
django.contrib.humanize
Django管理文檔生成器
分頁
使用Django輸出CSV
加密簽名
文件儲存API
安全
Django中的測試
國際化和本地化
為Django編寫首個補丁
條件表達式
日志
模型元選項
部署靜態(tài)文件
執(zhí)行查詢
使用Django認證系統(tǒng)
基于類的視圖
中間件
編寫自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫訪問優(yōu)化
錯誤報告
基于類的內(nèi)建通用視圖
編寫自定義存儲系統(tǒng)
編寫你的第一個 Django 程序 第3部分
編寫數(shù)據(jù)庫遷移
使用表單
編寫你的第一個 Django 程序 第2部分
編寫你的第一個 Django 程序 第1部分
如何使用會話
系統(tǒng)檢查框架
新手入門
信號
編寫視圖
如何使用WSGI 部署
編寫你的第一個Django應用,第6部分
常見的網(wǎng)站應用工具
Widgets
內(nèi)建的視圖
模型實例參考
視圖層
Django中的密碼管理
高級教程:如何編寫可重用的應用
國際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類)
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫函數(shù)
自定義查找
使用基于類的視圖處理表單
管理操作
開發(fā)過程
編寫你的第一個Django應用,第5部分
進行原始的sql查詢
模型層
多數(shù)據(jù)庫
編寫你的第一個 Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應用
按需內(nèi)容處理
管理器
視圖裝飾器
驗證器
使用Django輸出PDF
File對象
Django 的快捷函數(shù)
基于類的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

管理操作

簡而言之,Django管理后臺的基本流程是,“選擇一個對象并改變它”。在大多數(shù)情況下,這是非常適合的。然而當你一次性要對多個對象做相同的改變,這個流程是非常的單調(diào)乏味的。

在這些例子中,Django管理后臺可以讓你實現(xiàn)和注冊“操作” —— 僅僅只是一個以已選中對象集合為參數(shù)的回調(diào)函數(shù)。

在Django自帶的管理頁面中都能看到這樣的例子。Django在所有的模型中自帶了一個“刪除所選對象”操作。例如,下面是 django.contrib.auth app 在Django's創(chuàng)建的用戶模型:

../../../_images/user_actions.png

警告

“刪除所選對象”的操作由于性能因素使用了QuerySet.delete(),這里有個附加說明:它不會調(diào)用你模型的delete()方法。

如果你想覆寫這一行為,編寫自定義操作,以你的方式實現(xiàn)刪除就可以了 -- 例如,對每個已選擇的元素調(diào)用Model.delete()

關(guān)于整體刪除的更多信息,參見對象刪除的文檔。

繼續(xù)閱讀,來弄清楚如何向列表添加你自己的操作。

編寫操作

通過示例來解釋操作最為簡單,讓我們開始吧。

操作的一個最為普遍的用例是模型的整體更新??紤]帶有Article模型的簡單新聞應用:

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

我們可能在模型上執(zhí)行的一個普遍任務是,將文章狀態(tài)從“草稿”更新為“已發(fā)布”。我們在后臺一次處理一篇文章非常輕松,但是如果我們想要批量發(fā)布一些文章,會非常麻煩。所以讓我們編寫一個操作,可以讓我們將一篇文章的狀態(tài)修改為“已發(fā)布”。

編寫操作 函數(shù)

首先,我們需要定義一個函數(shù),當后臺操作被點擊觸發(fā)的時候調(diào)用。操作函數(shù),跟普通的函數(shù)一樣,需要接收三個參數(shù):

我們用于發(fā)布這些文章的函數(shù)并不需要ModelAdmin或者請求對象,但是我們會用到查詢集:

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

注意

為了性能最優(yōu),我們使用查詢集的update 方法。其它類型的操作可能需要分別處理每個對象;這種情況下我們需要對查詢集進行遍歷:

for obj in queryset:
    do_something_with(obj)

編寫操作的全部內(nèi)容實際上就這么多了。但是,我們要進行一個可選但是有用的步驟,在后臺給操作起一個“非常棒”的標題。通常,操作以“Make published”的方式出現(xiàn)在操作列表中 -- 所有空格被下劃線替換后的函數(shù)名稱。這樣就很好了,但是我們可以提供一個更好、更人性化的名稱,通過向make_published函數(shù)添加short_description 屬性:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

注意

這看起來可能會有點熟悉;admin的list_display選項使用同樣的技巧,為這里注冊的回掉函數(shù)來提供人類可讀的描述。

添加操作到 ModelAdmin

接下來,我們需要把操作告訴ModelAdmin。它和其他配置項的工作方式相同。所以,帶有操作及其注冊的完整的admin.py看起來像這樣:

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)

這段代碼會向我們提供admin的更改列表,看起來像這樣:

../../../_images/article_actions.png

這就是全部內(nèi)容了。如果你想編寫自己的操作,你現(xiàn)在應該知道怎么開始了。這篇文檔的剩余部分會介紹更多高級技巧。

在操作中處理錯誤

如果你預見到,運行你的操作時可能出現(xiàn)一些錯誤,你應該以優(yōu)雅的方式向用戶通知這些錯誤。也就是說,異常處理和使用django.contrib.admin.ModelAdmin.message_user()可以在響應中展示用戶友好的問題描述。

操作的高級技巧

對于進一步的選擇,你可以使用一些額外的選項。

ModelAdmin上的操作 ModelAdmin

上面的例子展示了定義為一個簡單函數(shù)的make_published操作。這真是極好的,但是以視圖的代碼設(shè)計角度來看,它并不完美:由于操作與Article緊密耦合,不如將操作直接綁定到ArticleAdmin對象上更有意義。

這樣做十分簡單:

class ArticleAdmin(admin.ModelAdmin):
    ...

    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.short_description = "Mark selected stories as published"

首先注意,我們將make_published放到一個方法中,并重命名 modeladmin 為self,其次,我們現(xiàn)在將'make_published'字符串放進了actions,而不是一個直接的函數(shù)引用。這樣會讓 ModelAdmin將這個操作視為方法。

將操作定義為方法,可以使操作以更加直接、符合語言習慣的方式來訪問ModelAdmin,調(diào)用任何admin提供的方法。

例如,我們可以使用self來向用戶發(fā)送消息,告訴她操作成功了:

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)

這會使動作與后臺在成功執(zhí)行動作后做的事情相匹配:

../../../_images/article_actions_message.png

提供中間頁面的操作

通常,在執(zhí)行操作之后,用戶會簡單地通過重定向返回到之前的修改列表頁面中。然而,一些操作,尤其是更加復雜的操作,需要返回一個中間頁面。例如,內(nèi)建的刪除操作,在刪除選中對象之前需要向用戶詢問來確認。

要提供中間頁面,只要從你的操作返回HttpResponse(或其子類)就可以了。例如,你可能編寫了一個簡單的導出函數(shù),它使用了Django的序列化函數(shù)來將一些選中的對象轉(zhuǎn)換為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

通常,上面的代碼的實現(xiàn)方式并不是很好。大多數(shù)情況下,最佳實踐是返回 HttpResponseRedirect,并且使用戶重定向到你編寫的視圖中,向GET查詢字符串傳遞選中對象的列表。這需要你在中間界面上提供復雜的交互邏輯。例如,如果你打算提供一個更加復雜的導出函數(shù),你會希望讓用戶選擇一種格式,以及可能在導出中包含一個含有字段的列表。最佳方式是編寫一個小型的操作,簡單重定向到你的自定義導出視圖中:

from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect

def export_selected_objects(modeladmin, request, queryset):
    selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
    ct = ContentType.objects.get_for_model(queryset.model)
    return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected)))

就像你看到的那樣,這個操作是最簡單的部分;所有復雜的邏輯都在你的導出視圖里面。這需要處理任何類型的對象,所以需要處理ContentType。

這個視圖的編寫作為一個練習留給讀者。

在整個站點應用操作

AdminSite.``add_action(action[, name])

如果一些操作對管理站點的_任何_對象都可用的話,是非常不錯的 -- 上面所定義的導出操作是個不錯的備選方案。你可以使用AdminSite.add_action()讓一個操作在全局都可以使用。例如:

from django.contrib import admin

admin.site.add_action(export_selected_objects)

這樣,export_selected_objects 操作可以在全局使用,名稱為“export_selected_objects”。你也可以顯式指定操作的名稱 – 如果你想以編程的方式移除這個操作 – 通過向AdminSite.add_action()傳遞第二個參數(shù):

admin.site.add_action(export_selected_objects, 'export_selected')

禁用操作

有時你需要禁用特定的操作 -- 尤其是注冊的站點級操作 -- 對于特定的對象。你可以使用一些方法來禁用操作:

禁用整個站點的操作

AdminSite.``disable_action(name)

如果你需要禁用站點級操作 ,你可以調(diào)用 AdminSite.disable_action()。

例如,你可以使用這個方法來移除內(nèi)建的“刪除選中的對象”操作:

admin.site.disable_action('delete_selected')

一旦你執(zhí)行了上面的代碼,這個操作不再對整個站點中可用。

然而,如果你需要為特定的模型重新啟動在全局禁用的對象,把它顯式放在ModelAdmin.actions 列表中就可以了:

# Globally disable delete selected
admin.site.disable_action('delete_selected')

# This ModelAdmin will not have delete_selected available
class SomeModelAdmin(admin.ModelAdmin):
    actions = ['some_other_action']
    ...

# This one will
class AnotherModelAdmin(admin.ModelAdmin):
    actions = ['delete_selected', 'a_third_action']
    ...

為特定的ModelAdmin禁用所有操作 ModelAdmin

如果你想批量_移除_所提供 ModelAdmin上的所有操作,可以把ModelAdmin.actions設(shè)置為None

class MyModelAdmin(admin.ModelAdmin):
    actions = None

這樣會告訴[ModelAdmin](index.html#django.contrib.admin.ModelAdmin ),不要展示或者允許任何操作,包括站點級操作。

按需啟用或禁用操作

ModelAdmin.``get_actions(request)

最后,你可以通過覆寫ModelAdmin.get_actions(),對每個請求(每個用戶)按需開啟或禁用操作。

這個函數(shù)返回包含允許操作的字典。字典的鍵是操作的名稱,值是 (function, name, short_description)元組。

多數(shù)情況下,你會按需使用這一方法,來從超類中的列表移除操作。例如,如果我只希望名稱以'J'開頭的用戶可以批量刪除對象,我可以執(zhí)行下面的代碼:

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

譯者:Django 文檔協(xié)作翻譯小組,原文:Admin actions

本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請保留作者署名和文章出處。

Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。