高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

更多關於Model的使用

在上一個章節的Shell操作過程中,如果你有注意到的話,你會發現一段長得像這樣的東西:

>>> Profile.objects.all()
[<Profile: Profile object>]

但如果你想讓這個object能夠一眼就看得出來它是什麼內容的話,只要在Model的Profile類別裡覆寫一些method,我們再次打開author/models.py,原來的程式碼長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models

# Create your models here.
class Profile(models.Model):
  name     = models.CharField(max_length = 50)
  age      = models.IntegerField()
  tel      = models.CharField(max_length = 30)
  address  = models.CharField(max_length = 100)
  email    = models.EmailField()

  class Meta(object):
    db_table = "profile"

我們來幫它加一個__unicode__的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.db import models

# Create your models here.
class Profile(models.Model):
  name     = models.CharField(max_length = 50)
  age      = models.IntegerField()
  tel      = models.CharField(max_length = 30)
  address  = models.CharField(max_length = 100)
  email    = models.EmailField()

  def __unicode__(self):
    return self.name

  class Meta(object):
    db_table = "profile"

然後我們再到shell裡操作的時候,就會發現秀出來的資料變得不一樣了:

>>> from author.models import Profile
>>> eddie = Profile(name = "eddie kao", age = 30, tel = "0928123123", address = "Taipei, Taiwan", email = "eddie@digik.com.tw")
>>> eddie
<Profile: eddie kao>

看到了嗎? 它由原本的object變成會秀出名字了。其實原理就是當你在Python用print方法把物件給印出來的時候,它會呼叫這個類別裡實作的__str____repr__以及__unicode__,其實這三個有一些些微的差異,細節可參考Python的文件說明,這裡我們直接覆寫Profile類別__unicode__方法,讓它回傳name欄位的值。這樣的修改,稍候你在後台看資料的時候,也會發現它會由原本的object,變成秀出你設定的name欄位。

事實上,你還可以定義更多的方法,把一些程式邏輯給包在Model裡,這樣一來,你在View(Controller)的地方就可以讓程式碼變得更簡潔,也更容易維護。例如我們來簡單寫個檢查該名作者是否已經成年(年齡 > 18):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.db import models

# Create your models here.
class Profile(models.Model):
  name     = models.CharField(max_length = 50)
  age      = models.IntegerField()
  tel      = models.CharField(max_length = 30)
  address  = models.CharField(max_length = 100)
  email    = models.EmailField()

  def is_adult(self):
    return self.age >= 18

  def __unicode__(self):
    return self.name

  class Meta(object):
    db_table = "profile"

再來進到shell裡看看:

> bookstore  python manage.py shell
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from author.models import Profile
>>> author = Profile.objects.get(id = 1)
>>> author
<Profile: eddie>
>>> author.is_adult()
True

原本你可能需要在View(Controller)層寫個if .. else ..來判斷,現在可以把這個判斷包在Model層裡,一來程式碼容易除錯,而且因為都集中在Model的話,萬一今天假設我們的法律把成年人條件改成滿20歲,你只要修改一下Model的邏輯判斷,其它程式碼不用修改就可以下班了,這樣感覺不是很歡樂嗎?

那個超佛心的管理後台呢?

記得我們在前面有提到Django有送我們一個很好用的後台管理系統嗎? 但那時候登入之後空空的什麼都沒有,接下來我們要來讓這個Profile類別在後台也可以管理。要讓Model在Admin模組可以看得到,有兩種做法,第一種是在App裡面新增一個admin.py,內容長得像這樣:

1
2
3
4
from django.contrib import admin
from author.models import Profile

admin.site.register(Profile)

這段程式碼的大意就是我們要把Profile類別給"註冊"到Admin模組裡,讓它也感覺得到它的存在。登入後台後,你應該可以看到Profile類別出現了:

image

你可以試著玩看看它的一些管理功能,試試從Admin模組去新增/修改/刪除/更新一些資料。除了剛剛在App裡新增admin.py之外,另一種做法就是把這個"註冊"的動作寫在Model裡,原來的Profile類別看起來會像這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.db import models
from django.contrib import admin

# Create your models here.
class Profile(models.Model):
  name     = models.CharField(max_length = 50)
  age      = models.IntegerField()
  tel      = models.CharField(max_length = 30)
  address  = models.CharField(max_length = 100)
  email    = models.EmailField()

  def is_adult(self):
    return self.age >= 18

  def __unicode__(self):
    return self.name

  class Meta(object):
    db_table = "profile"

class ProfileAdmin(admin.ModelAdmin):
  pass

admin.site.register(Profile, ProfileAdmin)

兩種做法都可以,我個人比較偏第二種,因為可以少寫一個檔案(懶!),程式碼只要在Model找就行了。

到目前為止,我們很單純的都只有一個表格,但現實生活不可能有這麼美好的事,所以我們再來新增一些資料表,並且讓這些資料表彼此有一些關連。

Comments