中秋快樂!新鮮出爐一篇DjangoAdmin使用合集,DjangoAdmin的功能比你想像的強大!
- 2022 年 9 月 10 日
- 筆記
- django, Python / Django
DjangoAdmin
DjangoAdmin本身就是一套大而全的系統,官方文檔中介紹了很多配置方法,但仍然有大量的騷操作是文檔中沒有的,所以遇到特殊需求的時候,求助文檔不一定有用。
在我看來 DjangoAdmin 雖然能快速生成一套管理後台,但如果要做大量特殊需求的訂製,其成本不亞於用 Vue/React 重新開發一套,簡單的使用成本不高,但深入訂製的話需要對 DjangoAdmin 的工作流程比較熟悉,把源碼啃熟了(有些 Python 源碼沒有類型註解是很難讀懂的),才能在原有基礎上雕花,有時候還存在著後續維護的問題。
不過還是瑕不掩瑜了,誰能拒絕配置了幾行程式碼就可以用的管理後台呢?
而且還不需要你做出一套 RESTFul API 來實現前後端分離,直接一把梭,起飛~
一些參考資料
- Django Admin 後台自訂製技巧://www.cnblogs.com/LyShark/p/12119539.html
- DjangoAdmin-欄位自動補全(django_admin_autocomplete_all 庫)使用與坑://django-admin-autocomplete-all.readthedocs.io/en/latest/readme.html
- DjangoAdmin添加自定義Widget://garmoncheg.blogspot.com/2014/07/django-adding-custom-widget-to-django.html
- How to Turn Django Admin Into a Lightweight Dashboard://hakibenita.com/how-to-turn-django-admin-into-a-lightweight-dashboard
介面主題
GitHub 上有很多 DjangoAdmin 的替換主題,所以不要抱怨 DjangoAdmin 的介面丑啦,好看的主題很多!
我最先使用的是 adminx,但這個侵入性太強了,需要對 admin 的配置程式碼做大量修改,實在是不划算,可能官方也意識到這個問題,後續應該是停更了。
到了 Django 2.x 時代後面,admin 的介面主題多了起來,有個國產的 SimpleUI 很不錯,基於 Vue + ElementUI 實現的,star很多,算是比較成熟的一類,我願稱之為國產之光。
其他的我也大多有測試,但用起來總有一些兼容的問題,所以目前還是比較推薦國產之光。
SimpleUI
已經在多個產品中使用,使用 vue+elementUI(非單頁應用),支援多標籤頁
一些相關的參考資料
- Django Admin SimpleUI 自定義列://simpleui.72wo.com/topic/1266
django-jazzmin
地址://github.com/farridav/django-jazzmin
這個是偶然發現的,對於看膩了 ElementUI 的人來說,會有眼前一亮的感覺
使用 Bootstrap+AdminLTE 重寫,效果還不錯
(就是偶爾會莫名卡死
而且細節方面做得不如 SimpleUI,比如搜索框沒有 placeholder 的提示之類的。
訂製案例
本文只記錄特殊需求的實現,對於 DjangoAdmin 的常規配置就不複製粘貼了,網上隨便一搜都有很多。
我之前已經寫過不少 DjangoAdmin 的訂製案例文章了,最近也做了不少訂製,不過我不想寫新文章來單獨記錄某個需求的實現過程了,直接在本文里記錄,同時保持本文更新~
- 給Django Admin添加驗證碼和多次登錄嘗試限制
- Django中間件之實現Admin後台IP白名單
- 給Django的Admin添加自定義Action 並移除需要選擇對象的限制
- 告別單調,Django後台主頁改造 – 使用AdminLTE組件
添加自定義列
本案例基於 SimpleUI
效果圖
實現過程
這裡使用的是 ElementUI 的 Tag 組件,文檔://element.eleme.cn/#/zh-CN/component/tag
前面提到過 SimpleUI 不是單頁應用,是直接在網頁上使用 vue 和 elementUI,並沒有webpack環境
所以要加入 elementUI 的組件不能直接簡單的
<el-tag type="success">標籤</el-tag>
而是要用 webpack 生成出來的
<div class="el-tag el-tag--success el-tag--light">標籤</div>
ok,開始上Python程式碼
假設有個 model 叫 Invoice
,中文名發票,定義如下
class Invoice(models.Model):
invoice_type = models.CharField('發票類型')
在需要自定義的 ModelAdmin 中,增加一個方法
# 發票類型顏色
@admin.display(description='發票類別')
def invoice_type_tag(self, obj: Invoice):
def el_tag(color_type, content):
"""
生成 ElementUI 的 tag 組件
:param color_type: success, info, warning, danger
:param content:
:return:
"""
from django.utils.safestring import mark_safe
type_class = '' if len(color_type) == 0 else f'el-tag--{color_type}'
return mark_safe(f'<div class="el-tag el-tag--small {type_class} el-tag--light">{content}</div>')
if obj.invoice_type.startswith('普通'):
return el_tag('', obj.invoice_type)
if obj.invoice_type.startswith('專用'):
return el_tag('danger', obj.invoice_type)
if obj.invoice_type.startswith('電子專票'):
return el_tag('info', obj.invoice_type)
if obj.invoice_type.startswith('電子普票'):
return el_tag('warning', obj.invoice_type)
然後把這個 invoice_type_tag
加到 list_display
中即可
PS:這裡的 @admin.display()
裝飾器是Django3.2版本之後新增的,很方便,相當於以前的
invoice_type_tag.short_description = '發票類別'
PS:注意HTML程式碼需要用 mark_safe
方法包裝起來,才能正常渲染,不然會被轉義!
顯示進度條
效果圖
實現過程
原理同上面的添加自定義列
程式碼如下
# 進度條
@admin.display(description='進度條')
def progress_bar(self, obj):
html = f'''
<div role="progressbar" aria-valuenow="{obj.progress}" aria-valuemin="0" aria-valuemax="100"
class="el-progress el-progress--line is-light el-progress--text-inside">
<div class="el-progress-bar">
<div class="el-progress-bar__outer" style="height: 22px;">
<div class="el-progress-bar__inner" style="width: {obj.progress}%;">
<div class="el-progress-bar__innerText">{obj.progress}%</div>
</div>
</div>
</div>
</div>
'''
from django.utils.safestring import mark_safe
return mark_safe(html)
頁面上顯示合計數額
效果圖
實現過程
這個功能比較麻煩,因為需要魔改 template
首先我們要知道,這個列表對應的是哪個 template,在 admin 包的 templates 目錄下面的找了半天,最終發現這個頁面是 change_list
,而且因為頁面比較複雜,被分成了好幾部分
我們只需要修改 change_list.html
這個文件就行了。
admin.py
OK,模板程式碼先不管,我們來寫Python程式碼計算總金額。
要實現將數據放在 context
里傳給 template,得重寫個 ChangeList
對象
from django.db.models import Sum
from django.contrib.admin.views.main import ChangeList
class InvoiceChangeList(ChangeList):
def get_results(self, request):
super(InvoiceChangeList, self).get_results(request)
totals = self.result_list.aggregate(Sum('amount'))
self.total_amount = totals['amount__sum']
使用 Sum
這個聚合方法,計算總金額。
通過Python語言的動態特性,加 total_amount
這個屬性添加到 ChangeList
對象中
這樣在 template 里就能通過 {{ cl.total_amount }}
的方式拿到這個屬性。
然後改一下 ModelAdmin :
class InvoiceAdmin(ImportExportModelAdmin):
# 如果你改了 template 的名稱,這裡可以對應修改,否則默認即可
change_list_template = 'change_list.html'
# 添加這個程式碼
def get_changelist(self, request, **kwargs):
return InvoiceChangeList
後端部分搞定了,接下來是前端的模板部分。
template
為了在頁面上添加新元素,我們來修改 change_list.html
文件。
注意,不要直接複製這個文件來修改!原因是你修改完的 template 會覆蓋其他組件,這樣以後換 admin 主題,或者使用 import-export 這類會修改 admin 頁面的插件時無法生效,也就是所謂的兼容問題。
Django也想到了這種情況,這些 template 都是組件化的,我們寫一個擴展 template 就可以了。
在項目的 templates/admin
目錄下新建 change_list.html
文件,程式碼如下
{% extends "admin/import_export/change_list.html" %}
{% block result_list %}
{{ block.super }}
<div style="text-align: right; margin: 20px 5px; font-size: 20px;">
總金額:{{ cl.total_amount }} 元
</div>
{% endblock %}
注意:如果用了 django-import-export 插件,則要根據使用到的功能來添加 object-tools-items
block。
比如你的 ModelAdmin 繼承自 ImportExportModelAdmin
,那我們轉到源碼,可以看到它重寫了 template
class ImportExportMixin(ImportMixin, ExportMixin):
"""
Import and export mixin.
"""
#: template for change_list view
change_list_template = 'admin/import_export/change_list_import_export.html'
class ImportExportModelAdmin(ImportExportMixin, admin.ModelAdmin):
"""
Subclass of ModelAdmin with import/export functionality.
"""
然後再看看 admin/import_export/change_list_import_export.html
這個文件
{% extends "admin/import_export/change_list.html" %}
{% block object-tools-items %}
{% include "admin/import_export/change_list_import_item.html" %}
{% include "admin/import_export/change_list_export_item.html" %}
{{ block.super }}
{% endblock %}
可以看到它在 object-tools-items
中添加了倆組件,把這一塊 block
的程式碼複製到我們的 change_list.html
中即可。
參考資料
擴展工具
這部分記錄我在逛GitHub時發現的比較有意思的擴展庫,記錄一下
Django AdminPlus
地址://github.com/jsocol/django-adminplus
可以方便的給admin增加新頁面
django-adminactions
地址://github.com/saxix/django-adminactions
可以給admin添加一系列的actions
- Export as CSV
- Export as Excel
- Export as fixture
- Export delete tree
- Mass update records
- Graph queryset
- Merge records
- Find Duplicates