almost 4 years ago

  • Admin介面
    • 設定settings.py
    • 設定urls.py
    • 建立admin的資料表
    • 建立superuser
    • 註冊模型
    • 模型欄位
  • admin管理功能與自定義ModelAdmin類別
    • 列表顯示
    • 列表過濾
    • 搜尋欄位
    • 排序
    • 自定義編輯欄位

本篇屬於一個可選的篇幅,讀者可以完全不利用到Django的admin來工作,但還是建議各位能夠看過本篇內容,其一是Django的admin實在是強大、好用且易用,其次是本篇中也順便包含了一些其他的知識,值得大家認識。

你是否覺得要利用shell為資料庫存入資料是件麻煩的事情呢?不僅要填寫欄位的內容,每一筆資料都得花時間在填寫欄位,這些重複的工作會讓網頁開發者覺得煩躁而無謂,當然,如果你建立的web app不需要初始資料庫(可能一開始為空之類的)且之後也不需要由管理者維持數據的話,應該是不會有什麼困擾,但大部分的情況不是這樣子的,所以我們必須得利用Admin(後台管理系統)!

Admin介面

當然對於後台我們可以從頭刻一個來使用,不過那太耗時間,而且這種每個開發者都會遇到的問題,你又何必重複發明輪子呢?如果你使用過php,那一定還記得phpMyAdmin吧,當初辛苦的安裝它,應該可以感受到它的好用,那你問Django,開玩笑,Django當然有Admin,而且是在你把Djanog安裝好的時候就一同被安裝好了!我們只需要將需要交由Admin的模型註冊給admin知道就好了,這一切相當簡單,我們跟著下列步驟一一學習如何啟動一個Admin:

設定settings.py

因為admin是Djanog中內建的一個app,為了將他安裝到專案上,我們打開settings.py:

mysite/mysite/settings.py
# 以上略...

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'restaurants',
)
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
# 以下略..

我們必須確認'django.contrib.admin'已經被我們填入INSTALLED_APPS中了,不過這通常是預設的,讀者們不必擔心。如果在模型那一篇,大家先將這些app安裝給註解掉了,這邊就一起打開註解,一次安裝所有應用吧!(由於admin與其他的內建app,如auth等有關,我們必須同時安裝相關的app)

另外,大家會發現,這些預設的app竟然都是來自於,contrib,可見他的重要性,不過我們這邊還不打算對contrib做全面的介紹,讀者只要專注在admin的部份即可。最後為了確保我們的admin是有用我們自己想要的語言,記得在MIDDLEWARE_CLASSES中加入'django.middleware.locale.LocaleMiddleware'且須置於'django.contrib.sessions.middleware.SessionMiddleware'後。

設定urls.py

接著我們打開urls.py,因為要在瀏覽器中開啟admin頁面,當然要設定一個對應到admin介面的pattern,很幸運的,Django在一開始就為我們做好了這件事,但我們有必要了解一下細節。

mysite/mysite/urls.py
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

from restaurants.views import menu

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^menu/$', menu),
)

第一個是要確定有從djanog.contrib中匯入admin,然後我們呼叫了admin.autodiscover這個函式,最後是在urlpatterns中,我們讓r'^admin/',對應到include(admin.site.urls),這個部分不懂很正常,因為我們還沒有提到巢狀的url結構,我們只要確定url(r'^admin/', include(admin.site.urls)),有在urlpatterns中就好。

完成了上述兩步,準備的工作便完成了。

建立admin的資料表

admin身為一個app,也是有自己的模型,更何況是他相依的一些app如auth等,所以一樣我們來將模型同步到資料庫並創建資料表吧。

還記得嗎,我們可以用validate來驗證模型:

$ python manage.py validate
0 errors found

如果有興趣可以看一下admin模型會生成的資料庫語法:

$ python manage.py sqlall admin

最後真正同步到資料庫(如果之前在模型那篇沒有註解掉admin應用的話,接下來的syncdb啥都不會做)

$ python manage.py syncdb

建立superuser

第一次安裝auth應用的話,你可能會在螢幕上看到這樣的提示:

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): 

你可以在此時便設定一個superuser的帳號,包括密碼和可選用的電子郵箱,你也可以稍後用:

$ python manage.py createsuperuser

來建立超級使用者。不過若要操作admin,你必須要至少有一個超級使用者,不然啥都沒有你要怎樣登入啦!

接下來的事情很簡單啦,運行server並且打開/admin/頁面,輸入帳號密碼(剛剛建立的超級使用者帳密),一個漂亮且內建的admin管理平台就出現在你我面前啦!讀者們可以隨意的點一點看一看,了解一下他頁面的設計,在user管理頁面中,我們還能新增更多的使用者或者調整個使用者的資料和權限,很簡單吧。等等!沒看到我的餐廳模型和食物模型阿,搞了一個資料庫管理平台出來,但是該管的東西沒出現怎麼可以!別擔心,那是因為我們還沒註冊啦!馬上打開restaurants專案中的admin.py來進行模型的註冊吧。

註冊模型

mysite/restaurants/admin.py
from django.contrib import admin
from restaurants.models import Restaurant, Food

admin.site.register(Restaurant)
admin.site.register(Food)

透過admin.site.register方法,便可以在admin介面中新增、檢視、編輯、刪除我們模型中的資料。當然我們要記得匯入admin本身(預設)還有各項想註冊的模型。建議讀者們可以親自試試看各種功能,並且為兩家餐廳多增加一些菜色,或是增加一些餐廳!

還記得我們在urls.py中讓admin去執行了autodiscover這個方法嗎?這會讓Django去掃視在設定檔中指名要安裝的app,如果該應用的目錄底下有admin.py,Django會執行其中的代碼,通常也就是註冊碼。

模型欄位

我們可以藉此觀察一下模型的欄位名稱,還記得在筆記(5)中的模型嗎?

class Restaurant(models.Model):
    name = models.CharField(max_length=20)
    phone_number = models.CharField(max_length=15)
    address = models.CharField(max_length=50, blank=True)

blank=True,允許該欄位為空白,我們會在admin的頁面中發現,Address這個欄位名稱並非粗體(其他兩個欄位都是粗體),而且在新增或編輯資料時,留空不會導致錯誤。

這邊要稍微深入探討一下留空的概念,在資料庫中,有兩種值都可能被稱為空白,一種是NULL,表示了空、無或是未知的、不合法的,另外一種是空字串,如果讀者還是不清楚,可以類比一下python中的None與空字串。有的時候這種差異和不一致會造成麻煩,舉例來說,我想找出所有有空白欄位的資料,我們對於使用NULL來檢查或是空字串來檢查可能會有疑義。

為了統一,Django在模型生成的時候會自動將各欄位設置為非NULL:NOT NULL

CREATE TABLE "restaurants_restaurant" (
    "id" integer NOT NULL PRIMARY KEY,
    "name" varchar(20) NOT NULL,
    "phone_number" varchar(15) NOT NULL,
    "address" varchar(50) NOT NULL
);

如此對於留白的欄位,我們便知道Django會寫入空字串到資料庫中,而不會是NULL了。但是這又產生了另外一個問題,日期跟時間的欄位是不允許空字串輸入的,為了留空,他必須允許NULL值的填入,解決的辦法是在模型撰寫時,用參數null=True來允許表格為NULL,結合以上兩點,對於一個可允許留空的時間日期欄位,我們必須同時指定blank=Truenull=True。不過對於已經生成好的資料表而言,我們若是回過頭要加入null=True的特性,又牽扯到資料表結構的異動,這部份便要留待之後說明。

date = models.DateField(blank=True, null=True)

欄位名稱還有一個玄機,我們會發現,Django會用以下規則為模型在admin中的欄位名稱命名。

欄位名稱 = 屬性名稱首字大寫 + 以空白取代屬性中的底線
e.g. phone_number => Phone number

如果大家不滿意這種命名規則,可以在模型中利用verbose_name來指定想要的名稱:

phone_number = models.CharField(max_length=15,verbose_name='poneNum')

不過我們通常不需要這麼做,除非一開始屬性名字取的太差。

admin管理功能與自定義ModelAdmin類別

admin管理平台的功能或是頁面呈現的樣子都是預設的,但我們其實可以針對我們理想中的介面進行客製化。這有賴於註冊模型於admin上時,要採用繼承於ModelAdmin的自定義類別。

列表顯示

第一點我們想要改變的是當我們在瀏覽資料表時,欄位顯示的不足,我們會發現,預設的全資料檢視介面裡,我們只能看到模型中的第一個屬性,以Restaurant為例,我們只能看到name,如果要瀏覽其他欄位的資料,必須點擊一筆資料,在編輯頁面中才能查詢的到,這個過程雖然簡單但不夠一目了然,有的時候,我們會向要一次瀏覽所有資料的某欄位值,如果要一筆一筆的點,實在累人,以下是解決的方法:

mysite/restaurant/admin.py
from django.contrib import admin
from restaurants.models import Restaurant, Food

class RestaurantAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone_number', 'address')

admin.site.register(Restaurant,RestaurantAdmin)
admin.site.register(Food)

在此代碼中,我們定義了一個繼承自admin.ModelAdmin的RestaurantAdmin類別,裡面我們使用了list_display這個元組變數,此元組裡面的每個元素都是一個字串而且要是模型欄位的名字。只要有指定在此元組的欄位,都會被顯示在admin中的全檢視頁面中,更方便的是,點擊列表的欄位名,會自動進行排序。

一個小叮嚀,再設定任何一個元組的時候,如果只有一個元素,請務必要加上一個,來避免誤會,切記切記。admin設置如果有誤可以先檢查一下是不是有單一元素的tuple沒有給定逗號。

列表過濾

過濾器讓我們能夠針對特定欄位的值,進行過濾,在全檢視頁面中只顯示特定欄位值的資料。可以放入列表過濾的資料欄位有

BooleanField
CharField
DateField
DateTimeField
IntegerField
ForeignKey
ManyToManyField

我們來看範例:

mysite/restaurant/admin.py
from django.contrib import admin
from restaurants.models import Restaurant, Food

class RestaurantAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone_number', 'address')
    
class FoodAdmin(admin.ModelAdmin):
    list_display = ('name', 'restaurant', 'price')
    list_filter = ('is_spicy',)

admin.site.register(Restaurant,RestaurantAdmin)
admin.site.register(Food, FoodAdmin)

我們會發現,檢視頁面中的右側加入了過濾器,對於is_spicy這個布林資料來說,他可以過濾出is_spicy為True的資料或是is_spicy為False的資料。另外,我們也為食物模型加入了list_display,外鍵restaurant也被允許出現在列表中。

搜尋欄位

當資料漸漸龐大,而我們想要檢視某部分特定的資料時,一個搜尋欄位對我們會很有幫助,直接看範例:

mysite/restaurant/admin.py
# 以上略...


class RestaurantAdmin(admin.ModelAdmin):
    list_display = ('name', 'phone_number', 'address')
    search_fields = ('name',)
    
# 以下略...

我們會在restaurant的檢視畫面上方看到一個搜尋欄位,而此欄位的搜尋將以name欄位為主,使用者們可以同時設定多個欄位。

排序

就如同前面所提,排序的方法千千萬萬種,不過這邊談的是在admin頁面中的排序,基本上資料表上資料的排序會依照我們之前提過的Metaclass來排序,如果有設定過Meta,該欄位名稱的旁邊應該會有個小三角形顯示排序,但事實上讀者若有設定list_display的話,每個欄位本身都能排序了。這邊要多嘴介紹一個排序的設定方法。一樣直接看範例:

mysite/restaurant/admin.py
# 以上略...


class FoodAdmin(admin.ModelAdmin):
    list_display = ('name', 'restaurant', 'price')
    list_filter = ('is_spicy',)
    ordering = ('-price',)
    
# 以下略...

設定ordering元組,指定欄位名稱,資料便會依照指定欄位進行排序,加入一個減號可以實現降序排序。

自定義編輯欄位

當我們點擊了一筆資料之後,便會進入編輯頁面,admin預設開放所有的欄位進行編輯,而順序也依照欄位當初被設置的順序,為了客製化這一點,我們可以利用fields元組。fields元組的元素也是資料欄位的名稱,其順序就是編輯頁面欄位出現的順序,而沒有出現在fields元組中的欄位,將不出現在編輯頁面中,無法被編輯。這可以有效地防止一些特定的資料無法被手動新增或修改。請看範例:

mysite/restaurant/admin.py
# 以上略...


class FoodAdmin(admin.ModelAdmin):
    list_display = ('name', 'restaurant', 'price')
    list_filter = ('is_spicy',)
    fields = ('price','restaurant')
    ordering = ('-price',)
    
# 以下略...

這將會使得price欄位出現在restaurant欄位之前,而且name、is_spicy和comment欄位都不會出現,不能被編輯。

其實還有更多的自定管理功能,如raw_id_fieldsfilter_horizontalfilter_verticaldate_hierarchy等,我們便不再此一一列舉,大家可以參閱Django官方的document。

下一篇我們將談到動態網站最重要的特性之一:如何跟使用者進行互動,這是web app中最有趣的部份,還等什麼呢?趕緊來瞧瞧。

← Django筆記(5) - 模型與資料庫 Django筆記(7) - 使用者互動與表單 →
 
comments powered by Disqus