本文源自 Reddit 上對我最近的一個帖子的評論:html
「問題是,我問到的每一個人都持反對意見,他們認爲 admin 只限於超級用戶,很不靈活而且是難以定製。」
—來自 Reddit 的 andybakgit
我如今要澄清這個誤解。Django 的 admin 絕對是軟件中的亮點,能夠有效的加速你的開發。github
這裏有一些我能想到的頗有用的 Django 的 admin 模塊的竅門。數據庫
(對於 Django admin 不太熟悉的人,先簡單解釋幾個名詞)django
Changeform 是能夠編輯對象的頁面。編程
Changelist 頁面能夠列出指定類型的對象。你能夠指定過濾對象的條件及對對象的操做。點擊 changelist 裏的對象通常會跳轉到對象的 changeform 頁面。安全
爲了讓這些敲門更具可操做性,咱們使用了與真實問題幾乎一致的場景。假設咱們有一個簡單的網站,訪客能夠上傳可愛的動物圖片並進行評論。這是否是很流行呢?架構
雖然 Django admin 管理界面能夠很是友好的用在 Django 項目的其它部分,它一樣能夠很容易用於其它像傳統的數據庫或具備一個可怕的的管理界面的網站。並且這也是評估 Django 是否會知足您的需求的最佳途徑。app
你須要作的僅是:ide
在你的 Django 項目中創建一個新的應用,並確保你已經鏈接好傳統數據庫 ,經過 settings.py 文件中的 DATABASES 的設置。
將你的數據表定義爲 Django 的模型。正如它的名字所表述的,manage.py inspectdb 是一個很是有用的命令:檢測現有的數據庫,並打印出自動生成的 Django 模型。
建立 admin.py 文件,並放在那裏,唉,管理相關的。稍後將詳細說明這個。
說到咱們的動物「的網站,是由進屎的腦殼寫出來的,因此管理界面看起來像……你知道的,不是很好。爲了解決這個問題,咱們經過幾個 Django 模型重構了數據庫結構,實現一個簡單的管理界面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# models.py class Picture(models.Model): DOG = 1 CAT = 2 ANIMAL_KIND_CHOICES = ( (DOG, 'dog'), (CAT, 'cat'), )
title = models.CharField(max_length=200) author = models.ForeignKey(Author, related_name='pictures') animal_kind = models.IntegerField(choices=ANIMAL_KIND_CHOICES) photo = models.ImageField(upload_to='animals') is_promoted = models.BooleanField(default=False)
class Author(models.Model): name = models.CharField(max_length=100) email = models.EmailField()
class Comment(models.Model): author = models.ForeignKey(Author, related_name='comments') picture = models.ForeignKey(Picture, related_name='comments') comment = models.TextField() editors_note = models.TextField()
# admin.py class PictureAdmin(admin.ModelAdmin): list_display_fields = ('photo', 'animal_kind', 'author', 'is_promoted', )
class AuthorAdmin(admin.ModelAdmin): list_display_fields = ('name', 'email', )
class CommentAdmin(admin.ModelAdmin): list_display_fields = ('picture', 'author', ) |
不少人使用 Django admin 後臺對指定字段進行篩選。要知道,把一個字段名放到 list_filter 列表裏就能夠了。同時它也很是容易地建立一個自定義過濾器!
假如最終你決定要推廣全部有 100+ 的帖子的做者。可是,咱們如何區分它們?讓咱們建立一個過濾器,並把它添加到咱們的變動列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class ProductiveAuthorsFilter(admin.SimpleListFilter): parameter_name = 'is_productive' title = 'Productive author' YES, NO = 1, 0
# Number of comments for an author to be considered a productive one THRESHOLD = 100
def lookups(self, request, model_admin): return ( (self.YES, 'yes'), (self.NO, 'no'), )
def queryset(self, request, queryset): qs = queryset.annotate(Count('comments'))
# Note the syntax. This way we avoid touching the queryset if our # filter is not used at all. if self.value() == self.YES: return qs.filter(comments__count__gte=self.THRESHOLD) if self.value() == self.NO: return qs.filter(comments__count__lt=self.THRESHOLD)
return queryset
class PictureAdmin(admin.ModelAdmin): list_filters = [..., ProductiveAuthorsFilter] |
如今,咱們能夠很容易地選出咱們的核心做者。那麼咱們如何開始向他們推廣呢?讓咱們進入下一部分。
這但是內容管理者的天賜之物。還記得在每一個模型的列表頂部的「動做」工具欄不?咱們是否是很是方便的先選擇一些圖片,而後只需單擊一下就「推廣」給做者了?如今讓咱們來實現它:
1 2 3 4 5 6 7 |
class PictureAdmin(admin.ModelAdmin): actions = ['promote', ]
def promote(self, request, queryset): queryset.update(is_promoted=True) self.message_user(request, 'The posts are promoted') promote.short_description = 'Promote the pictures' |
就是這樣!不用再一個挨一個的打開每一個表單!另外,它很容易進一步增長咱們的動做,例如,添加一個過渡表單。關於這點,Django 文檔 有段很是棒的講解。
好吧,過濾器是很酷,但讓咱們關注了一下就搜索工具。在幾乎全部的安裝我見過的搜索框是用來在一個模型中的字段搜索。可是,當你意識到它能夠處理關係的 Django 搜索真正的亮點。所以,假設咱們但願它在圖片「的標題,做者姓名和註釋」文本進行搜索。咱們如何作到這一點?
1 2 |
class PictureAdmin(admin.ModelAdmin): search_fields = ('title', 'author__name', 'comments__text', ) |
若是你的數據庫是夠大,不要忘記添加一些全文索引來增長搜索速度。
在站點查看一個對象的界面是很是普及的需求,默認狀況下,你必須打開該對象的表單,而後點擊按鈕「在站點查看」。如下代碼展現如何使此過程更容易一些:
1 2 3 4 5 6 7 8 |
class PictureAdmin(admin.ModelAdmin): list_fields = [..., 'object_link']
def object_link(self, item): url = item.get_absolute_url() return u'<a href={url}>open</a>'.format(url=url) object_link.short_description = 'View on site' object_link.allow_tags = True |
這段代碼給列表中每一個對象都添加了「在站點查看」的連接。在此,咱們假定你的模型(Model)已經實現了get_absolute_url()方法。若是尚未 – 那如今就去實現 ,這將爲你節省不少時間。你也可能會想將這個片斷轉移到一個 mixin,或公用的 admin 基類。
假設咱們須要給評論加一個編輯的備註。很天然,咱們但願不須要對每條評論都去打開評論的changeform。要作到這點,咱們能夠稍微修改一下ModelAdmin:
1 2 3 |
class CommentAdmin(admin.ModelAdmin): list_display_fields = ('picture', 'author', 'editors_note', ) list_editable = ('editors_note', ) |
這樣就搞定了,如今打開評論列表,能夠按照須要進行過濾,還能夠在評論上即時添加備註。
每一個 changelist 最下方都有一行列出總數(total)。假設咱們須要把貓和狗的圖片數量區分開來。這個功能須要的代碼稍微多一些:咱們須要重載 changelist 和 html 模板(更多內容參考模板重載)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from django.contrib.admin.views.main import ChangeList
class PicturesChangeList(admin.ChangeList): def get_results(self, request): super(PicturesChangeList, self).get_results(request) totals = self.result_list.aggregate( dogs_count=Sum(Case(When(animal_kind=Picture.DOG, then=1), output_field=IntegerField())), cats_count=Sum(Case(When(animal_kind=Picture.CAT, then=1), output_field=IntegerField()))) self.totals = totals
class PictureAdmin(admin.ModelAdmin): def get_changelist(self, request): return PicturesChangeList |
模板的內容:
1 2 3 4 5 6 7 8 9 10 11 12 |
{% extends 'admin/change_list.html' %} {% block result_list %} {{ block.super }} <p> There are <strong> {{ cl.totals.dogs_count|default:'none' }} dogs and {{ cl.totals.cats_count|default:'none' }} cats </strong> on this page. </p> {% endblock %} |
啥意思?假設你的祖母打算瞅一眼這些可愛的圖片,她站在你背後,以爲 Django 的 admin 界面挺有意思。不過你能確定,她要是使用 admin 界面,恐怕一個按鈕的點擊就能毀掉整個網站。那麼,咱們加上 grandma-proof™,這樣就支持只讀的 admin 界面(就是某人說的「數據瀏覽」):
1 2 3 4 5 6 7 8 9 |
class GrandmaProofAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): if request.user.username == 'granny': return [f.name for f in self.model._meta.fields] else: return super(GrandmaProofAdmin, self).get_readonly_fields(request, obj)
class PictureAdmin(GrandmaProofAdmin): ... |
如今你能夠安全的把修改圖片的權限放開給你的祖母,這樣她就能瀏覽圖片列表。要注意這個方案確定不能適用於全部使用場景,你還須要處理更多的狀況。
有時候你須要在單個對象上執行特定的 action。‘actions’工具固然能夠完成這個任務,不過過程會顯得很麻煩:點擊對象、選擇 action、再點擊一個按鈕……確定有更便捷的方式,對吧?讓咱們想辦法只點擊一次就所有搞定。
此次咱們要實現老祖母的另外一個宏達的想法。她但願能給某些編輯發 email,告訴他們她喜歡的全部圖片。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class PictureAdmin(admin.ModelAdmin): list_fields = (..., 'mail_link', )
def mail_link(self, obj): dest = reverse('admin:myapp_pictures_mail_author', kwargs={'pk': obj.pk}) return '<a href="{url}">{title}</a>'.format(url=dest, title='send mail') mail_link.short_description = 'Show some love' mail_link.allow_tags = True
def get_urls(self): urls = [ url('^(?P<pk>\d+)/sendaletter/?$', self.admin_site.admin_view(self.mail_view), name='myapp_pictures_mail_author'), ] return urls + super(PictureAdmin, self).get_urls()
def mail_view(self, request, *args, **kwargs): obj = get_object_or_404(Picture, pk=kwargs['pk']) send_mail('Feel the granny\'s love', 'Hey, she loves your pet!', 'granny@yoursite.com', [obj.author.email]) self.message_user(request, 'The letter is on its way') return redirect(reverse('admin:myapp_picture_changelist')) |
希望她如今可以滿意。如今每一個對象字段加上了一個連接,讓她點一下就能夠發送郵件。
Django admin (Django 也是如此) 最經常使用也是最有用的技巧是 select_related。呃,你已經都知道了?不就是把對象的名字傳給 ModelAdmin 的 list_select_related 屬性來實現相關對象的預加載嘛。可是,你知道你並無描述所有的相關對象嗎?只須要設置成 True,Django 就能夠自動預加載外部對象:
1 2 |
class PictureAdmin(admin.ModelAdmin): list_select_related = True |
問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com
QQ羣290551701 彙集不少互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!