本文首發於公眾號:Hunter後端 原文鏈接:Django筆記三十五之admin後臺界面介紹 這一篇介紹一下 Django 的後臺界面使用。 Django 自帶了一套後臺管理界面,可用於我們直接操作資料庫數據,本篇筆記目錄如下: 創建後臺賬號以及登錄操作 註冊後臺顯示的數據表 列表欄位的顯示操作 字 ...
本文首發於公眾號:Hunter後端
這一篇介紹一下 Django 的後臺界面使用。
Django 自帶了一套後臺管理界面,可用於我們直接操作資料庫數據,本篇筆記目錄如下:
- 創建後臺賬號以及登錄操作
- 註冊後臺顯示的數據表
- 列表欄位的顯示操作
- 欄位值的修改操作
- 列表頁的執行操作
1、創建後臺賬號以及登錄操作
首先我們需要創建一個可以訪問後臺的賬號,以下命令在系統的根目錄下進行:
python3 manage.py createsuperuser
然後他會提示我們輸入賬號的名稱,郵箱以及兩遍密碼用於確認。
Username (leave blank to use 'hunter'): admin
Email address: [email protected]
Password:
Password (again):
在這個過程中,如果我們輸入的密碼少於8位或者過於簡單,他會給我們提示說密碼過於簡單等,可以設置複雜點的,也可以直接確認。
創建好賬號密碼後,運行我們的系統:
python3 manage.py runserver 0:9898
然後就可以在瀏覽器里訪問我們的後臺系統了:
http://localhost:9898/admin
在下麵的圖裡輸入賬號密碼就可以進入系統了:
這裡需要註意一點的是,如果你是按照我們的筆記一路操作過來,在前面我們的用戶登錄限制里可能限制了 login 和 register 介面才允許不登錄,那麼我們在相應的驗證中間件里可以簡單做一下操作:
class AuthMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
path = request.path
# url 路徑為 /users/register 和 /users/login 的介面不需要進行判斷驗證
if path not in [
"/users/register",
"/users/login",
]:
if path.startswith("/admin"):
return self.get_response(request)
session = request.session
if not session.get("username"):
return JsonResponse({"code": -1, "msg": "not login"}, status=401)
response = self.get_response(request)
return response
這裡我們將 /admin 開頭的介面都設置為了不需要登錄驗證。
2、註冊後臺顯示的數據表
輸入賬號密碼登錄後臺系統後,如果之前沒有做過後臺註冊的相關操作的話,可能只會看到 Django 系統自帶的 Users 和 Groups 表,它們是預設在後臺顯示的。
如果你點擊進入 Users 表,可以看到我們剛剛創建的這個用於登錄的管理員賬號 admin。
如果我們想要使得我們創建的其他表也在後臺顯示,則需要手動去註冊一下。
註冊的流程很簡單,我們這裡以 blog 這個 application 為例,修改 blog/admin.py,對於需要顯示的表,我們直接使用 admin.site.register() 操作,即可在後臺顯示,比如:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
admin.site.register(Blog)
重啟系統後,就可以看到多了一個 Blog 的 application 以及其下的 Blog 表了。
再點擊進入表,可以看到一條條 Blog 表裡的數據了,但是表的欄位在列表頁都是被隱藏的,只有在點擊進入單條數據詳情頁時,才會顯示具體的欄位值。
3、列表欄位的顯示操作
前面介紹瞭如何註冊一個 model,使其在後臺界面顯示,但是有一個問題就是數據列表每條都只有一個欄位表示,而沒有每個欄位的具體值顯示,接下來我們就對具體欄位值的顯示做介紹。
首先,我們使用的 model 定義如下:
class Blog(models.Model):
PUBLISHED = 1
UNPUBLISHED = 0
PUBLISHED_STATUS = (
(PUBLISHED, "published"),
(UNPUBLISHED, "not_published"),
)
name = models.CharField(max_length=100, unique=True)
tag_line = models.TextField()
char_count = models.IntegerField(verbose_name="文章字數", default=0)
is_published = models.BooleanField(choices=PUBLISHED_STATUS, default=UNPUBLISHED)
pub_datetime = models.DateTimeField(verbose_name="發佈日期", null=True, default=None)
定義好後的 migration 相關操作可以自己去完成。
註冊操作
前面介紹了 model 在後臺顯示的註冊操作:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
admin.site.register(Blog)
但是這種操作只能在後臺顯示列表信息,具體的欄位信息不會在列表顯示,如果要實現這種操作,我們需要進行另一種註冊方式:
# blog/admin.py
from django.contrib import admin
from blog.models import Blog
class BlogAdmin(admin.ModelAdmin):
pass
admin.site.register(Blog, BlogAdmin)
接下來,我們的具體操作都會在 BlogAdmin 中實現。
列表顯示欄位
如果我們想要在列表中就顯示數據的具體欄位,比如 id, name,is_published,pub_datetime 三個欄位,我們可以使用 list_display 屬性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "pub_datetime")
重啟系統後,就可以在列表看到相應的欄位顯示了:
註意:在這裡,is_published 這裡直接顯示了該欄位的用於顯示的值,這個和之前介紹的 get_field_display() 的方式是一致的。
可以看到,這個列表的表頭就是我們定義的 model 里的 verbose_name 的值,如果沒有定義該屬性,則會直接顯示欄位名。
數據格式化顯示
可以註意到日期的顯示並不利於直觀的查看,所以可以對日期欄位做一個格式化處理返回顯示。
以下是對 model 的處理:
# blog/models.py
from django.contrib import admin
class Blog(models.Model):
# 欄位在這裡省略
pass
@admin.display(description="發佈時間")
def format_pub_datetime(self):
return self.pub_datetime.strftime("%Y-%m-%d %H:%M:%S")
以下是對 BlogAdmin 的處理:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
這樣在列表頁就會多一列,表頭為【發佈時間】。
這裡我們其實可以這樣理解,我們對 Blog 這個 model 添加了一個名為 format_pub_datetime 的屬性,這個屬性用 admin.display() 作為裝飾器,這個屬性可以作為被 admin 的 list_display 使用作為列表的展示項。
在這裡我們是直接對 pub_datetime 欄位做格式化處理,當然也可以對非時間欄位做其他的處理,主要看想要實現的效果。
註意: 這裡還有需要註意的一點是,pub_datetime 欄位是允許為 null 的,所以這裡最好是做一下適配處理,比如說 return 的時候判斷一下:
@admin.display(description="發佈時間")
def format_pub_datetime(self):
return self.pub_datetime.strftime("%Y-%m-%d %H:%M:%S") if self.pub_datetime else ""
上面這種方式是在 model 下定義的函數,我們也可以直接在 BlogAdmin 定義該函數操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
@admin.display(description="發佈時間")
def format_pub_datetime(self, obj):
return obj.pub_datetime.strftime("%Y-%m-%d %H:%M:%S") if obj.pub_datetime else ""
列表數據排序
列表的數據預設是按照 id 的倒序排列返回的,如果想要按照其他欄位排序返回,比如 char_count,可以使用 ordering 屬性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
ordering = ("char_count",)
如果是想要倒序排列,欄位前加一個 - 即可:
ordering = ("-char_count",)
4、欄位值的修改操作
如果我們想要在 admin 的頁面修改數據的欄位值,目前我們能做的操作就是點擊每條數據前面的 id,他會進入這條數據的詳情頁,每個欄位都是預設可修改的。
指定欄位點擊進入編輯頁
我們也可以指定某個,或者某幾個欄位進入這條數據的詳情頁進行編輯,用到的屬性是 list_display_links,這個屬性的值預設是 id 主鍵欄位,但如果我們想點擊 id 和 name 欄位的時候都進入詳情頁,可以如下操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
list_display_links = ("id", "name",)
直接在列表頁面修改欄位值
如果某個欄位是需要經常修改的,我們想要在列表頁面就修改而不用進入數據的詳情頁,可以加上 list_editable 屬性,比如我們直接在列表頁修改 name 欄位的值:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
list_editable = ("name", )
需要註意的是,list_editable 和 list_display_links 這兩個屬性是相斥的,也就是說這兩個的欄位列表不能擁有同一個欄位值。
詳情頁欄位的顯示與否
點擊進入數據的編輯詳情頁,預設所有欄位是可以修改的,如果想要某些欄位在詳情頁顯示或者不顯示,可以使用 fields 和 exclude 屬性,分別表示顯示和不顯示的欄位。
顯示 name 和 is_published 欄位:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
fields = ("name", "is_published")
隱藏 name 和 is_published 欄位:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
exclude = ("name", "is_published")
欄位僅可讀
有一些比較重要的欄位,如果在詳情頁不希望能夠被修改,可以使用 readonly_fields 屬性,比如不希望 name 欄位被修改:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "format_pub_datetime")
readonly_fields = ("name",)
重啟系統後,就可以在列表頁看到 name 欄位沒有修改框,為僅可讀狀態了。
註意: 需要提醒的一點是,上面所有的添加欄位屬性的操作的值都需要是列表或者元組。
save_as 屬性
save_as,這是一個在數據詳情頁保存時的屬性,目前進入數據的詳情頁,右下角有三個按鈕,左邊的第一個是 save_and_add_another
,意思是保存操作之後會自動進入新的頁面,可用於創建數據。
當我們設置 save_as=True 之後:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
save_as = True
再看這三個按鈕,第一個按鈕就會變成 save as new
,意思是在原數據上修改了之後,點擊可以保存為一條新數據,原數據保持不變。
這個操作過程可以理解成我們前面一篇筆記中介紹如何新建一條數據的方式,就是在原數據上將 id 欄位變成 None 然後進行 save 操作,就會在原數據的基礎上創建一條新數據。
這個過程可以去看 Django筆記的第十八篇中自增的主鍵那一段。
5、列表頁的執行操作
在列表頁,目前僅有一個可供執行的操作,那就是選中 id 那一欄的數據之後,點擊 action 旁邊的下拉框,有一個 delete 操作,意思是刪除選中的數據:
快速搜索過濾操作
對於某些值的種類比較少的數據,比如 is_published 欄位,或者日期欄位,想要實現快速搜索的操作,可以使用 list_filter 屬性:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
list_filter = ("is_published", "pub_datetime")
重啟系統後可以看到列表頁面右側出現了一個篩選列表:
對於非日期欄位,這裡有一些固定的日期的選擇,對於其他欄位,則是會列出所有欄位值作為篩選項。
指定欄位搜索
如果想要對某個或者某幾個欄位進行模糊搜索,可以使用 search_fields 屬性,比如想要搜索 name 和 pub_datetime 欄位:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
search_fields = ("name", "pub_datetime")
重啟系統後,頁面的左上角會出現一個搜索框,比如我們搜索 python
,就會去查找 name 和 pub_datetime 欄位中包含 python
的數據。
如果我們搜索的時候使用空格將搜索的關鍵字分隔開,那麼系統會自動為我們進行 split() 操作,然後搜索,比如這裡我們搜索的是 python 2021
,那麼系統轉化的 sql 就會是:
where (name like '%python%' or pub_datetime like '%python%') and (name like '%2021%' or pub_datetime like '%2021%')
如果希望搜索的內容是一個整體,可以使用單引號或者雙引號括起來 'python 2021'
日期分級篩選
前面介紹了一個快速搜索過濾的操作,這裡針對於日期欄位介紹一下另一種篩選過濾的方式,比如我們對 pub_datetime 欄位進行操作:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
date_hierarchy = "pub_datetime"
重啟系統後,可以在頁面左上角看到 2021,2022,2023 幾個年份,都是根據當前表裡的數據統計出來的結果,然後點擊進入相當於是進行了一次年份的篩選,在第二層頁面繼續點擊選擇則是一次新的篩選:
save_model()
前面在 Django筆記第十八篇中有介紹過一條數據的保存 save() 操作的繼承處理,我們可以通過自定義一些邏輯使得數據在保存前進行一些操作,在這裡,save_model() 的操作也可以提供同樣的功能:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
def save_model(self, request, obj, form, change):
print("do something")
super().save_model(request, obj, form, change)
actions 自定義執行任務
假設說我們想要實現一些批量執行的操作,比如選中列表頁某些數據,將 is_published 欄位批量更新成 True(即已發佈),我們就可以用到 actions 來實現。
目前在頁面的左上角有一個 action 和旁邊的下拉框,系統實現了一個預設的函數邏輯,即刪除選中項,我們可以來實現一個更新選中項的功能:
class BlogAdmin(admin.ModelAdmin):
list_display = ("id", "name", "is_published", "char_count", "format_pub_datetime")
actions = ["make_published"]
@admin.action(description="make queryset published")
def make_published(self, request, queryset):
queryset.update(is_published=True)
使用 admin.action 作為裝飾器來裝飾一個函數,然後將函數名稱作為值放入 actions 列表中,在這裡 queryset 參數即為頁面選中的數據,它是一個 queryset 類型,所以這裡可以直接進行 update() 操作。
如果想執行一些更深入的操作,我們也可以對 request 參數進行操作解析,它即為我們前端選中執行傳過來的請求。
重啟系統後,刷新頁面,點開 action 旁邊的下拉框,就可以看到我們定義的函數了,選中數據,點擊旁邊的 Go
按鈕即可執行。
可以定義多個執行函數,記得添加到 actions 列表進行註冊即可。
如果想獲取更多後端相關文章,可掃碼關註閱讀: