最近收到了一些 Request 要把之前用 Django Admin 搞的後台做一些 improve
雖然用了 Django 一陣子可是覺得自己還是只懂皮毛而已,還有蠻多奇奇怪怪的功能都沒用過
之前就聽說 Admin 的 layout 除了常見的那些欄位跟 filter 顯示,
其他都可以客製化,可是改起來頗麻煩,剛好趁這次機會紀錄一下改法。
其實官網文件都有寫,不過我還是先從思考方向先記錄起。
從何下手
首先我從 source code 下手想看看 Admin 裡面到底是怎麼把各 page render 出來,
到底哪些東西是可以調哪些不能調,個人覺得這招搭配看文件很有用。
所以就直接殺到的 django/contrib/admin/templates/
哦!沒錯就是這邊!
Admin 的各種 template 全都放在這,看來就是從這下手了!
以我這次要改的部分叫做 submit_line.html
為例,
我想透過參數去控制 submit row 在某些 model 下會出現新的客製 action。
所以我就看到 django/contrib/admin/templatetags/admin_modify.py
發現裡面有一個 function 是來控制這件事,
先附上 code:
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
| @register.inclusion_tag('admin/submit_line.html', takes_context=True) def submit_row(context): """ Displays the row of buttons for delete and save. """ opts = context['opts'] change = context['change'] is_popup = context['is_popup'] save_as = context['save_as'] show_save = context.get('show_save', True) show_save_and_continue = context.get('show_save_and_continue', True) ctx = { 'opts': opts, 'show_delete_link': ( not is_popup and context['has_delete_permission'] and change and context.get('show_delete', True) ), 'show_save_as_new': not is_popup and change and save_as, 'show_save_and_add_another': ( context['has_add_permission'] and not is_popup and (not save_as or context['add']) ), 'show_save_and_continue': not is_popup and context['has_change_permission'] and show_save_and_continue, 'is_popup': is_popup, 'show_save': show_save, 'preserved_filters': context.get('preserved_filters'), } if context.get('original') is not None: ctx['original'] = context['original'] return ctx
|
看到這邊就得到我的結論:Submit row 的按鈕都可以透過 admin.py 的參數設定去做開關,但是只限於原本就有的那些 action,如果你要新增 action button 或是某些特殊邏輯才 show 的話還是要透過 overwrite 的方式去做才可以!
Overwrite admin template
從剛剛的 source code 看到我要做兩件事,自訂 template 跟 自訂 tag
自訂 template
官網文件 The Django admin site
開一個資料夾 MYAPP/templates/admin
把要 overwrite 的 template 丟進去
change_form.html
1 2 3 4 5
| {% extends "admin/change_form.html" %} {% load custom_submit_line %} {% block submit_buttons_bottom %}{% custom_submit_line %}{% endblock %}
|
這邊可以發現我定義了一個 tag 叫做 custom_submit_line
並且把原本在 admin/change_form.html
內的
1
| {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
|
submit_row
overwrite 成 custom_submit_line
custom_submit_line.html
1 2 3 4 5 6 7 8 9 10 11 12
| {% load i18n admin_urls %} <div class="submit-row"> {% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %} {% if show_delete_link %} {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %} <p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p> {% endif %} {% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{% endif %} {% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %} {% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %} {% if show_something %}<input type="submit" value="{% trans 'Aloha!' %}" name="_custom" />{% endif %} </div>
|
最後別忘了在 settings.py
內設定一下 TEMPLATES 的 DIR 參數
不然會噴 not found 的錯誤!
自訂 tag
官網文件 Custom template tags and filters
開一個資料夾 MYAPP/APP_NAME/templatetags
把要 overwrite 的 tag 丟進去
custom_submit_line.py
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import os from django import template CURRENT_PATH = os.path.dirname(os.path.realpath(__file__)) SUBMIT_LINE_HTML = os.path.normpath( os.path.join(CURRENT_PATH, '../../templates/admin/custom_submit_line.html') ) register = template.Library() @register.inclusion_tag(SUBMIT_LINE_HTML, takes_context=True) def custom_submit_line(context): """ Displays the row of buttons for delete and save. """ opts = context['opts'] change = context['change'] is_popup = context['is_popup'] save_as = context['save_as'] show_save = context.get('show_save', True) show_save_and_continue = context.get('show_save_and_continue', True) ctx = { 'opts': opts, 'show_delete_link': ( not is_popup and context['has_delete_permission'] and change and context.get('show_delete', True) ), 'show_save_as_new': not is_popup and change and save_as, 'show_save_and_add_another': ( context['has_add_permission'] and not is_popup and (not save_as or context['add']) ), 'show_save_and_continue': not is_popup and context['has_change_permission'] and show_save_and_continue, 'is_popup': is_popup, 'show_save': show_save, 'preserved_filters': context.get('preserved_filters'), } if context.get('original') is not None: ctx['original'] = context['original'] if opts.model_name == 'card': ctx['show_something'] = True return ctx
|
跟原本的長很像我只有在最後做了一些邏輯,
然後把 template 換成 custom_submit_line.html
如此而已!
這樣就完成了客製化工作啦~
後記
Trace 了 source code 之後發現幾乎每一個頁面都可以客製化,真心覺得 django admin 很方便,
幫我處理掉了很多冗事,但是它裡面的邏輯很多都設計好了,要改的話要小心把預設的邏輯改爆。
如果真的要改很大的話,也許自己寫會方便許多,按照專案需求決定會是比較好的選擇!
Reference
- 某個 Github Repo