做web開發,編碼往往以模組化開始,下面以django1.5為标準,扯扯寫一個道地的django model.(django1.4絕大部分可以相容)
1.首先要對Field Options有個基本的認識(屬性是面向model類而言的,字段是面向資料庫而言的)
model由屬性field組成,不同field類型,有不同的options,先了解所有field都公共的options。官網有比較多的options,選取正常開發能用到的幾個說一說。
null選項, 表示資料庫層面的檢驗,能否為null,預設為False,就是說資料庫裡這個屬性對應的字段預設不能存儲null
blank選項,能否為空值empty value(不是None空對象),None存到資料庫就是null,這個選項與資料庫無關,是一個純django層面的檢驗,比如form的校驗,能否允許empty value就取決于這個選項
choices選項,指定這個屬性的值隻能是哪幾種可能,具體寫法看文檔https://docs.djangoproject.com/en/1.5/ref/models/fields/#django.db.models.Field.choices
db_column選項,指定資料庫表裡這個屬性對應字段的名字,預設是屬性名字,無特殊需要,不用理會。如果實際需要更改,比如使用一個已經存在的資料庫,確定名字可用
db_index選項,是否為這個屬性對應字段添加索引,即使有這個需要,unique可以勝任
default,不用說了,賦預設值
editable,是否可編輯,預設true,如果不可編輯,将不會再model-form和admin中的添加修改出現
error_messages,該屬性使用者輸入不符合要求時,提示資訊,預設已有,除非不滿足你的要求,不用理會。
help_text,幫助資訊,當使用者輸入填寫表單時,提示使用者這個該怎麼輸入
verbose_name,官網有個解釋很好A human-readable name for the field。簡略的說:屬性名cat,verbose_name=U"貓",那麼頁面上就顯示貓,不是cat
2.寫好每一個屬性
1.數值字元串類型:大整數使用 BigIntegerField
一般IntegerField
确定值很小 可以節約空間使用 SmallIntegerField
浮點數,高精度浮點,字元串,布爾,IP,郵箱,URL,等等分别使用其對應類型即可,另外有些帶Positive修飾,檢驗正負,總之一句話:請使用最精确的類型。
此外CommaSeparatedIntegerField不是整數,别被名字騙了,本質還是字元串
大量文本使用TextField,個人覺得百K是上限,再大過M就不适合了
更大,那就自定義類型,指向底層資料庫支援的大資料類型,這個比較簡單。
2.日期時間類型:DateField,TimeField,DateTimeField
如果你要記錄首次添加時間,auto_now_add=True
如果你要記錄最後更新時間,auto_now=True,這兩個就不要自己動腦筋實作了
但是注意QuerySet批量更新時,不是依次調用每個對象的更新函數,不會觸發auto_now,批量更新其他字段時記得連帶更新最後時間
3.上傳檔案,使用FileField相關文檔太長,簡要概括
upload_to指定上傳目錄,storage如何管理你上傳的檔案,預設就夠用。有幾個可選,看看差異即可。
但是,models類讀取檔案屬性和普通屬性有所差別:
讀取檔案屬性傳回值是一個FieldFile對象,代表你上傳的檔案,這個對象的url屬性表示檔案路徑,open,close,delete,save方法用于操作檔案。
此外FilePathField與檔案基本無關,也别被名字騙了,本質是個字元串,隻不過要求這個字元串表示的檔案路徑正确有效,有些選項可以控制檔案或目錄,不詳述。
ImageField是FileField子類,隻不過加了幾個與圖檔相關的控制參數,用法一樣
4.外鍵,比如
1.class Comment(models.Model):
target = models.ForeignKey(XXX)#XXX另一個model 類,表示對XXX的一個評論
如果外鍵要指向自己,比如要表示對評論的評論,使用self,或者自己的類名parent =models.ForeignKey('self')或者models.ForeignKey('Comment')
parent就表示上一級評論,使用字元串表示類名,在程式運作時,這個類名必須能在ContentType找到,簡單點說,就是存在并且被django加載了。不了解django的ContentType沒關系,不需要用django内置的一些玩意就用不着。
2.related_name,指定反向查找時的key,舉例:
上例中xxx.comment_set.all()可以取出該XXX的所有評論,是因為預設related_name就是類名Comment的全小寫comment+"_set",預設就夠使用了
什麼時候必須指定呢?上面的model添加兩個屬性
from_user =models.ForeignKey(User, related_name='from_me')
to_user =models.ForeignKey(User, related_name='to_me')
此時如不指定related_name就會報錯,因為django不知道該如何反向取值了。如果按照上面分别指定了related_name,那麼外鍵反向取值,如下
user.from_me.all()就能取出我發出的所有評論
user.to_me.all()取出所有發給我的評論
3.limit_choices_to 沒啥說的,限制外鍵取值範圍
4.to_field,是指外鍵指向另一個表(模型)的哪一個字段(屬性),預設指向主鍵id.可以修改指向别的字段(屬性),不過確定其唯一性
5.on_delete是說外鍵指向的對象删除時,本對象應該采取的措施,預設級聯删除。
一共有cascade, protect, set_null, set_default, set(), do_nothing等選擇,詳見https://docs.djangoproject.com/en/1.5/ref/models/fields/#django.db.models.ForeignKey.on_delete
5.多對多
跟外鍵差不多,隻說不同的。
1. symmetrical,對稱性。比如User有個多對多鍵friends指向User,我添加你做朋友,自動地,你也是我的朋友,這就是對稱性,預設為true,開啟。
可以設定False,關閉後,我添加你做朋友,我的好友清單有你。你的好友清單沒有我。
2.through,過渡表。django預設的多對多實作是采用中間過渡表完成。比如A多對多B,那麼有張中間表
id:中間表自己的主鍵
a_id:指向A表主鍵
b_id指向B表主鍵
用這張過渡表記錄AB的多對多關系。很遺憾,這張表就隻有三個字段,不能記錄其他資訊,比如我是什麼時間添加你做朋友。想要存儲額外資訊到過渡表,就該 使用through了。官網有個例子https://docs.djangoproject.com/en/1.5/topics/db/models/#intermediary-manytomany
3.db_table,過渡表表名。如上文,AB多對多過渡表表名預設為a_b,二者類名下劃線連結,再小寫。你可以指定其他名字。
6.一對一,跟外鍵幾乎一樣,多一個選項(options),叫parent_link,沒啥大作用。給個位址看看官網解釋https://docs.djangoproject.com/en/1.5/ref/models/fields/#django.db.models.OneToOneField.parent_link
3.最後一點了,Meta設定
abstract 用來指定是否是抽象類,抽象類不會生成表,适合用于面向對象的基類
app_label預設不用指定,django自省即可(别問什麼是自省啊,有百度可以問)。當你的model定義在models.py或者models包外時,或者是動态模型,那就必須指定了,值就是你的app名字即可。關于動态模型,詳見django dynamic models and field injections
db_table預設值是“appName”+“_”+ “modelName”,可以指定别的表名。使用已存在的庫表時有用。
get_latest_by,指定django的latest函數取最新記錄時預設按什麼排序
ordering指定模型預設按什麼排序,注意此設定會反映到資料庫層面,并且會有外鍵傳遞影響
permissions指定該模型需要額外建立的權限代碼,預設add change delete 三種
unique_together 指定資料庫表中哪幾列必須組合起來唯一,不能全部相同。同聯合主鍵。
index_together 指定資料庫表中哪幾列必須組合起來建立索引。與unique_together唯一差別在于不要求組合唯一。
verbose_name給你的模型取一個好了解的好閱讀的名字在頁面上顯示,
verbose_name_plural是verbose_name的複數,預設verbose_name+“s“
proxy order_with_respect_to不常用,managed一般不需改變,有需要可看看文檔
充分利用django内置的實作完成你的功能,不要自己苦思冥想去實作一些偏僻的功能,而且盡最大可能寫最精确的代碼,就OK了。