Django 爲將來的開發人員提供了許多功能:一個成熟的標準庫,一個活躍的用戶社區,以及 Python 語言的全部好處。雖然其餘 Web 框架也聲稱能提供一樣的內容,但 Django 的獨特之處在於它內置了管理應用程序 —— admin。html
admin 提供了開箱即用的高級 Create-Read-Update-Delete (CRUD) 功能,減小了重複工做所需的時間。這是許多 Web 應用程序的關鍵所在,程序員能夠在開發時快速瀏覽他們的數據庫模型;非技術最終用戶能夠在部署時使用 admin 添加和編輯站點內容。python
在現實中,總須要執行某些定製操做。關於 admin 外觀的基本狀況,Django 文檔提供許多指南,Django 自身也包含了一些簡單的方法用來改寫 admin 行爲的子集。若是您須要更多功能怎麼辦呢?從哪裏開始着手呢?本文將指導您如何進行一些高級 adimin 定製。程序員
大多數 Django 開發人員都很熟悉 admin 的默認功能。讓咱們快速回顧一下,首先編輯頂級 urls.py 啓用 admin,見清單 1。shell
1
2
3
4
5
6
7
8
9
|
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root),
)
|
您還須要將 django.contrib.admin
應用程序添加到 settings.INSTALLED_APPS
。安全
在繼續下一步前,建議計劃擴展 admin 的用戶熟悉一下源代碼。對於支持快捷鍵和符號連接的操做系統,建立一個指向 admin 應用程序的快捷鍵或符號連接會頗有用。服務器
admin 包含在 Django 包中。假如已經使用安裝工具安裝了 admin,則它位於 django/contrib/admin 下的 site-packages 中。如下是一個項目到 Django admin 源的符號連接樣例,您能夠根據操做系統和 Django 安裝的位置定製,以便更輕鬆的複製和引用:app
$ ln -s /path/to/Python/install/site-packages/django/contrib/admin admin-source
admin.autodiscover()
方法迭代設置 .INSTALLED_APPS 中的每一個應用程序,並查找名爲 admin.py 的文件。該文件一般位於應用程序目錄的最上方,與 models.py 級別同樣。
樣例應用程序須要清單 2 中提供的 models.py。相應的 admin.py 以下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
from django.db import models
class Document(models.Model):
'''A Document is a blog post or wiki entry with some text content'''
name = models.CharField(max_length=255)
text = models.TextField()
def __unicode__(self):
return self.name
class Comment(models.Model):
'''A Comment is some text about a given Document'''
document = models.ForeignKey(Document, related_name='comments')
text = models.TextField()
|
如今,您能夠經過運行 Django 開發服務器調用 admin:
1
|
python manage.py runserver
|
admin 可從默認位置 http://localhost:8000/admin/ 獲取。登陸以後,您能夠看到基本的 admin 屏幕,以下所示。
注意,您的模型如今尚不可用,由於您尚未建立 admin.py。清單 3 展現的代碼讓您能在 admin 中使用模型。
1
2
3
4
5
6
7
8
9
10
11
|
from django.contrib import admin
from more_with_admin.examples import models
class DocumentAdmin(admin.ModelAdmin):
pass
class CommentAdmin(admin.ModelAdmin):
pass
admin.site.register(models.Document, DocumentAdmin)
admin.site.register(models.Comment, CommentAdmin)
|
如今若是您在 admin 中重載主頁,您將看到可用的新模型,以下所示。
理解在不修改 Django 源代碼的狀況下如何定製 admin 的關鍵在於,記住 admin 像其餘程序同樣只是一個普通的 Django 應用程序。最重要的一點是,這意味着可使用 Django 模版繼承系統。
Django 的模版搜索順序老是將您本身項目的模版排在其餘系統以前。此外,admin 在恢復到默認狀況前,會嘗試搜索匹配每一個模型的硬編碼模版。這爲輕鬆定製提供了一個擴展點。
首先,確保 Django 經過編輯項目的 settings.py 來查看您的模版目錄。
1
2
3
4
|
TEMPLATE_DIRS = (
"/path/to/project/more_with_admin/templates",
"/path/to/project/more_with_admin/examples/templates",
)
|
而後在項目中建立如下目錄:
1
2
|
$ mkdir templates/admin/examples/document/
$ mkdir templates/admin/examples/comment/
|
Django admin 的特殊行爲將檢查目錄和應用程序名稱(這裏是 examples
),而後是模型的名稱(document
和 comment
),而後才能使用系統模版呈現該管理頁面。
admin 用來添加和編輯模型實例的頁面名稱是 change_form.html。首先在 Document
模型目錄中建立一個名爲 templates/admin/examples/document/change_form.html 的頁面,而後將 Django 模版繼承線置入其中:{% extends "admin/change_form.html" %}
。
如今能夠進行定製了。花一些時間熟悉實際的 admin/change_form.html 的內容。它很合理地將一些能夠重寫的模板塊組織到一塊兒,可是有些定製可能須要大量複製模塊。不過,使用基於塊的模板重寫老是比複製整個頁面要好。
您想對添加/編輯頁面執行哪一種定製?對於系統中的每一個 Document
,您應該展現 5 個最近評論的預覽。
首先,建立一些樣例內容。
Document
1
2
3
4
5
6
|
$ python manage.py shell
In [1]: from examples import models
In [2]: d = models.Document.objects.create(name='Test document',
text='This is a test document.')
In [3]: for c in range(0, 10):
...: models.Comment.objects.create(text='Comment number %s' % c, document=d)
|
如今,admin 列表頁面展現一個 Document
。選擇該 Document
打開默認的添加/編輯頁面,以下所示。
Document
的默認添加/編輯頁面
注意,相關評論不顯示。在 admin 中顯示相關模型的標準方法是使用強大的 Inline
類。Inline
類容許 admin 用戶在單個頁面編輯或添加多個相關模型。要查看運行的 inline
,按照清單 6 編輯應用程序 admin.py。
Document
admin 添加相關模型評論
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from django.contrib import admin
from more_with_admin.examples import models
class CommentInline(admin.TabularInline):
model = models.Comment
class DocumentAdmin(admin.ModelAdmin):
inlines = [CommentInline,]
class CommentAdmin(admin.ModelAdmin):
pass
admin.site.register(models.Document, DocumentAdmin)
admin.site.register(models.Comment, CommentAdmin)
|
圖 4 展現了添加 TabularInline
控件以後新的添加/編輯頁面。
Inline
添加以後的添加/編輯頁面
這無疑很是強大,可是若是隻想快速預覽評論的話就不必這樣作了。
這裏您能夠採起兩種方法。一種是使用 Django admin widget 接口編輯與 inline
關聯的 HTML widget;Django 文檔詳細描述了 widget。另外一種方法是直接修改添加/編輯頁面。若是不但願使用任何特定於 admin 的功能,那麼該方法很是有用。
若是不容許編輯評論(多是因爲用戶沒有足夠的權限),可是又想 讓用戶看到評論,那麼能夠修改 change_form.html。
要在模型實例頁面添加功能,您須要瞭解 admin 已經可使用什麼數據。兩個鍵變量的說明以下。
列出沒法直接輸入 Django 模板的相關評論查詢代碼。最佳的解決方案是使用模板標記。首先,建立模板標記目錄 and __init__.py 文件:
1
2
|
$ mkdir examples/templatetags/
$ touch examples/templatetags/__init__.py
|
建立一個名爲 examples/templatetags/example_tags.py 的新文件,並添加如下代碼。
1
2
3
4
5
6
7
8
9
10
|
from django import template
from examples import models
register = template.Library()
@register.inclusion_tag('comments.html')
def display_comments(document_id):
document = models.Document.objects.get(id__exact=document_id)
comments = models.Comment.objects.filter(document=document)[0:5]
return { 'comments': comments }
|
因爲這是一個包含標籤,您須要建立相應的模板文件:comments.html。編輯 examples/templates/comments.html 文件並輸入清單 8 中的代碼。
1
2
3
|
{% for comment in comments %}
<
blockquote
>{{ comment.text }}</
blockquote
>
{% endfor %}
|
如今能夠將它添加到 admin 頁面了。在 admin.py 中註釋掉對 CommentInline
的引用,並按照清單 9 更改 change_form.html 的本地版本。
1
2
3
4
5
6
7
|
{% extends "admin/change_form.html" %}
{% load example_tags %}
{% block after_field_sets %}
{% if object_id %}{% display_comments object_id %}{% endif %}
{% endblock %}
|
在使用前檢查 object_id
的存在很重要,由於 change_form.html 還能夠用來建立新實例,在這種狀況下 object_id
不可用。after_field_sets
塊只是 admin 中提供的衆多擴展點之一。其餘請參考 change_form.html 源頁面。
圖 5 展現了更新後的表格。
模板重寫只能作這麼多了。若是您想更改 admin 的實際流和行爲怎麼辦呢?修改源代碼不是不可能,可是那會讓您受制於更新時使用的特定 Django 版本。
AdminModel
方法默認狀況下,在 admin 中單擊 Save 將用戶帶回到列表頁面。一般這沒有問題,可是若是您想直接到 admin 外部的對象預覽頁面,那應該怎麼辦?在開發內容管理系統 (CMS) 時這種狀況很常見。
admin 應用程序中的大部分功能都附加到 admin.ModelAdmin
類。這是該對象從 admin.py 中繼承的類。您能夠重寫許多許多公開方法。類定義請查看 admin-source/options.py 中的源代碼。
有兩種方法能夠更改 Save 按鈕的行爲:您能夠重寫 admin.ModelAdmin.response_add
,該按鈕負責保存後的實際重定向;還能夠重寫 admin.ModelAdmin.change_view
。後一種方式更爲簡單。
1
2
3
4
5
6
7
8
9
10
11
12
|
class DocumentAdmin(admin.ModelAdmin):
def change_view(self, request, object_id, extra_context=None):
result = super(DocumentAdmin, self).change_view(request, object_id, extra_context)
document = models.Document.objects.get(id__exact=object_id)
if not request.POST.has_key('_addanother') and
not request.POST.has_key('_continue'):
result['Location'] = document.get_absolute_url()
return result
|
如今用戶單擊 Save 時,他們將被指向預覽頁面,而不是展現全部 Documents 的列表頁面。
signals 是 Django 中較少使用的功能,它能夠提升代碼的模塊化程度。signals 定義保存模型或加載模板的事件,不管它在哪裏運行,Django 項目均可以偵聽到並對它作出反應。這意味着您能夠輕鬆的提升應用程序的行爲,而無需直接修改它們。
admin 提供了一個應用程序開發人員常常想修改的功能:經過 django.contrib.auth.models.User
類管理用戶。Django 用戶每每只能添加或修改 admin,這使得這個有用的類很難定製。
想象一下,您但願每次建立一個新的 User
對象時,站點管理員都能收到一封電子郵件。由於 User
模塊沒法直接在項目中使用,實現該目標的惟一方法彷佛是子類化 User
或者使用間接方法,好比建立虛擬配置文件對象進行修改。
清單 11 展現了在保存 User
實例時添加運行的函數有多麼簡單。signals 一般被添加到 models.py。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
from django.db import models
from django.db.models import signals
from django.contrib.auth.models import User
from django.core.mail import send_mail
class Document(models.Model):
[...]
class Comment(models.Model):
[...]
def notify_admin(sender, instance, created, **kwargs):
'''Notify the administrator that a new user has been added.'''
if created:
subject = 'New user created'
message = 'User %s was added' % instance.username
from_addr = 'no-reply@example.com'
recipient_list = ('admin@example.com',)
send_mail(subject, message, from_addr, recipient_list)
signals.post_save.connect(notify_admin, sender=User)
|
post_save
signal 由 Django 提供,每次保存或建立模型時都會激活。connect()
方法帶有兩個參數:一個回調參數(notify_admin
)和 sender
參數,後者指定該回調只關注 User
模型的保存事件。
在回調中,post_save
signal 傳遞發送方(模型類)、該模型的實例和提示是否剛剛建立了實例的布爾值。在本例中,若是建立了 User
,該方法將發送一封電子郵件;不然不執行任何操做。
有關其餘 Django 提供的 signals 列表,請參見 參考資料,以及介紹如何編寫 signals 的文檔。
一個經常使用的 Django admin 特性是它的權限系統,該系統能夠擴展以包含低級權限。默認狀況下,admin 能夠細粒度控制角色和權限,可是這些角色僅應用於類級別:用戶能夠修改全部 Document 或不修改任何 Document。
每每只容許用戶修改特定的對象。這經常稱爲低級 權限,由於它們只能修改特定數據庫表格行,而綜合權限能夠修改表格中的任何記錄。樣例應用程序中的狀況多是您只但願用戶看到他們建立的 Document。
首先,更新 models.py 以包含建立 Document
的屬性記錄,以下所示。
Document
的用戶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from django.db import models
from django.db.models import signals
from django.contrib.auth.models import User
from django.core.mail import send_mail
class Document(models.Model):
name = models.CharField(max_length=255)
text = models.TextField()
added_by = models.ForeignKey(User,
null=True, blank=True)
def get_absolute_url(self):
return 'http://example.com/preview/document/%d/' % self.id
def __unicode__(self):
return self.name
[...]
|
接下來,須要添加代碼自動記錄哪一個用戶建立了 Document
。signals 沒法用於這種狀況,由於 signal 沒有訪問用戶對象。可是,ModelAdmin
類提供了一個方法,使用該請求和當前用戶做爲參數。
修改 admin.py 中的 save_model()
方法,以下所示。
DocumentAdmin
中的方法,以在建立數據庫時保存當前用戶
1
2
3
4
5
6
7
8
9
|
from django.contrib import admin
class DocumentAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if getattr(obj, 'added_by', None) is None:
obj.added_by = request.user
obj.last_modified_by = request.user
obj.save()
[...]
|
若是 added_by
的值是 None
,那麼這就是一個還沒有保存的新記錄。(您還能夠檢查 change
是否爲 false
,這指示是否將添加記錄,可是檢查 added_by
是否爲空表示是否填寫添加到 admin 以外的記錄)。
另外一個低級權限是將文檔列表限制在建立它們的用戶範圍內。ModelAdmin
類爲此提供了一個鉤子程序 —— 它有一個名爲 queryset()
的方法,該方法能夠肯定任何列表頁面返回的默認查詢集。
如清單 14 所示,重寫 queryset()
以便將清單限制在當前用戶建立的這些 Document 中。超級用戶能夠看到全部文檔。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from django.contrib import admin
from more_with_admin.examples import models
class DocumentAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(DocumentAdmin, self).queryset(request)
# If super-user, show all comments
if request.user.is_superuser:
return qs
return qs.filter(added_by=request.user)
[...]
|
如今,任何對 admin 中 Document
列表頁面的查詢只顯示當前用戶建立的文檔(除非當前用戶是高級用戶,這種狀況下將顯示全部文檔)。
固然,只要知道 ID,用戶就能夠訪問編輯頁面查看未受權的文檔,當前對此沒有任何阻止手段。真正安全的低級權限須要重寫更多方法。由於 admin 用戶一般都達到某種水平的信任,因此有時一些基本的權限便足以提供精簡的工做流了。
定製 Django admin 不須要 admin 源代碼知識,也不須要修改源代碼。admin 可使用普通的 Python 繼承和一些 Django 特有功能(好比 signals)進行擴展。
經過建立全新管理界面定製 admin 的優勢不少: