4. 創(chuàng)建 django 博客的數(shù)據(jù)庫模型

本教程內(nèi)容已過時,更新版教程請訪問: Django 博客開發(fā)入門教程

這是 Django 博客教程的第 4 篇,在閱讀此篇教程以前疆导,請確保你已閱讀 Django 博客教程的前 3 篇:
1. Django 博客教程:前言
2. 搭建開發(fā)環(huán)境
3. 建立我們的 django 博客應(yīng)用

編寫博客的數(shù)據(jù)庫模型

博客最主要的功能就是展示我們寫的文章,它需要從某個地方獲取我們寫的博客文章數(shù)據(jù)才能把它展示出來葛躏,通常來說這個地方就是數(shù)據(jù)庫澈段。我們把寫好的文章永久地保存在數(shù)據(jù)庫里,當(dāng)用戶訪問我們的博客時舰攒,django 就去數(shù)據(jù)庫里把這些數(shù)據(jù)取出來展現(xiàn)給用戶败富。

博客的文章應(yīng)該含有標(biāo)題、正文摩窃、作者兽叮、發(fā)表時間等數(shù)據(jù),一個更加現(xiàn)代化的博客文章我們也希望它有分類猾愿、標(biāo)簽鹦聪、評論等。為了更好地存儲這些數(shù)據(jù)蒂秘,我們需要合理地組織我們數(shù)據(jù)庫的結(jié)構(gòu)泽本。

我們的博客初級版本主要包含這些數(shù)據(jù):博客文章,文章會有分類以及標(biāo)簽姻僧。一篇文章只能有一個分類规丽,但可以打上很多標(biāo)簽。數(shù)據(jù)庫存儲的數(shù)據(jù)其實(shí)就是表格的形式撇贺,例如存儲我們的博客文章的數(shù)據(jù)庫表長這個樣子:

文章 id 標(biāo)題 正文 發(fā)表時間 分類 標(biāo)簽
1 title1 text1 2016-12-23 django django 學(xué)習(xí)
2 title2 text2 2016-12-24 django django 學(xué)習(xí)
3 title3 text3 2016-12-26 Python Python 學(xué)習(xí)

其中 id 是一個數(shù)字赌莺,唯一對應(yīng)著一篇文章。當(dāng)然還可以在列上加入更多的信息显熏,這只是一個最基本的示例雄嚣。

數(shù)據(jù)庫表設(shè)計成這樣其實(shí)已經(jīng)可以了晒屎,但是稍微分析一下我們就會發(fā)現(xiàn)一個問題喘蟆,這 3 篇文章的分類和標(biāo)簽都是相同的,這會產(chǎn)生很多重復(fù)數(shù)據(jù)鼓鲁,當(dāng)數(shù)據(jù)量很大時就浪費(fèi)了存儲空間蕴轨。不同的文章可能它們的分類或者標(biāo)簽是相同的,所以我們把分類和標(biāo)簽?zāi)贸鰜砗Э裕龀蓡为?dú)的數(shù)據(jù)庫表橙弱,再把文章和分類與標(biāo)簽關(guān)聯(lián)起來就可以了。下面分別是分類和標(biāo)簽的數(shù)據(jù)庫表:

分類 id 分類名
1 django
2 Python
標(biāo)簽 id 標(biāo)簽名
1 django 學(xué)習(xí)
2 Python 學(xué)習(xí)

以上是自然語言描述的表格,數(shù)據(jù)庫也和編程語言一樣棘脐,有它自己的一套規(guī)定的語法來生成上述的表格結(jié)構(gòu)斜筐,這樣我們才能把數(shù)據(jù)存進(jìn)去。一般情況下這時候我們應(yīng)該先去學(xué)習(xí)數(shù)據(jù)庫創(chuàng)建表格的語法蛀缝,再回來寫我們的博客程序了顷链。但是 django 跟我們說不用這么麻煩,我已經(jīng)幫你做了一些事情屈梁,我把那一套數(shù)據(jù)庫的語法轉(zhuǎn)換成了 Python 的語法形式嗤练,你寫你的 Python 代碼就可以了,翻譯的工作我來幫你在讶。用更加專業(yè)一點(diǎn)的說法煞抬,就是 django 為我們提供了一套 ORM(Object Relational Mapping)系統(tǒng)。比如說我們的分類數(shù)據(jù)庫表构哺,django 只要求我們這樣寫:

blog/models.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=100)

這就是一個標(biāo)準(zhǔn)的 Python 的類革答,我們繼承了 models.Model 類,類名為 Category(分類)遮婶,Category 類有一個屬性 name蝗碎,它是 models.CharField 的一個實(shí)例。這樣旗扑,django 就可以把這個類翻譯成數(shù)據(jù)庫的語法蹦骑,在數(shù)據(jù)庫里創(chuàng)建一個名為 category 的表格,這個表格的一個列名為 name(即分類名)臀防,還有一個列 id 則會自動幫我們創(chuàng)建眠菇。其規(guī)則就是一個 Python 類對應(yīng)一個數(shù)據(jù)庫表格,類名即表名袱衷,類的屬性對應(yīng)著表格的列捎废,屬性名即列名。我們需要 3 個表格:文章(Post)致燥、分類(Category)以及標(biāo)簽(Tag)登疗,下面就來創(chuàng)建它們。已經(jīng)在代碼中做了詳細(xì)的注釋嫌蚤,說明每一句代碼的含義辐益。但如果你在移動端下閱讀不便的話,也可以跳到代碼后面看正文的里的講解脱吱。

blog/models.py

from django.db import models
from django.contrib.auth.models import User


class Category(models.Model):
    """
    django 要求我們必須繼承 models.Model 類智政,
    Category 只需要一個簡單的分類名 name 就可以了。

    CharField 指定了 name 的數(shù)據(jù)類型箱蝠,
    CharField 是字符型续捂,
    max_length 指定其最大長度垦垂,
    超過這個長度的分類名就不能被存入數(shù)據(jù)庫。

    當(dāng)然 django 還為我們提供了各種各樣的類型牙瓢,
    如日期時間類型 DateTimeField劫拗、
    整數(shù)類型 IntegerField 等等。
    django 內(nèi)置的類型全部類型可查看文檔:
    https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types
    """
    name = models.CharField(max_length=100)


class Tag(models.Model):
    """
    標(biāo)簽 Tag 也比較簡單矾克,
    和 Category 一樣杨幼。
    再次強(qiáng)調(diào)一定要繼承 models.Model 類!
    """
    name = models.CharField(max_length=100)


class Post(models.Model):
    """
    文章的數(shù)據(jù)庫表稍微復(fù)雜一點(diǎn)聂渊,主要是涉及的字段更多差购。
    """

    # 文章標(biāo)題
    title = models.CharField(max_length=70)

    # 文章正文,我們使用了 TextField汉嗽。
    # 比較短的字符串存儲可以使用 CharField欲逃,
    # 但對于文章的正文來說可能會是一大段文本,
    # 因此使用 TextField 來存儲大段文本饼暑。
    body = models.TextField()

    # 這兩個列分表表示了文章的創(chuàng)建時間和最后一次修改時間稳析,
    # 存儲時間的列用 DateTimeField。
    created_time = models.DateTimeField()
    modified_time = models.DateTimeField()

    # 文章摘要弓叛,可以沒有文章摘要彰居,
    # 但默認(rèn)情況下 CharField 要求我們必須存入數(shù)據(jù),
    # 否則就會報錯撰筷。
    # 指定 blank=True 后就可以允許空值了陈惰。
    excerpt = models.CharField(max_length=200, blank=True)

    # 這是分類與標(biāo)簽,
    # 分類與標(biāo)簽的模型我們已經(jīng)定義在上面毕籽。
    # 我們在這里把文章對應(yīng)的數(shù)據(jù)庫表和分類與標(biāo)簽對應(yīng)的表關(guān)聯(lián)起來抬闯,
    # 但是關(guān)聯(lián)形式稍微有點(diǎn)不同。
    # 我們規(guī)定一篇文章只能對應(yīng)一個分類关筒,
    # 但是一個分類下可以有很多篇文章溶握,
    # 所以我們使用的是 ForeignKey,
    # 即一對多的關(guān)系蒸播。
    # 而對于標(biāo)簽來說睡榆,
    # 一篇文章可以有多個標(biāo)簽,
    # 同一個標(biāo)簽下也可能有多篇文章袍榆,
    # 所以我們使用 ManyToManyField胀屿,
    # 表明這是多對多的關(guān)系。
    # 同時我們規(guī)定文章可以沒有標(biāo)簽蜡塌,
    # 因此為標(biāo)簽 tags 指定了 blank=True碉纳。
    # 如果你對 ForeignKey勿负、ManyToManyField 不了解馏艾,
    # 請看教程中的解釋劳曹,
    # 亦可參考官方文檔:
    # https://docs.djangoproject.com/en/1.10/topics/db/models/#relationships
    category = models.ForeignKey(Category)
    tags = models.ManyToManyField(Tag, blank=True)

    # 文章作者
    # 這里 User 是從 django.contrib.auth.models 導(dǎo)入的。
    # django.contrib.auth 是 django 內(nèi)置的應(yīng)用琅摩,
    # 專門用于處理網(wǎng)站用戶的注冊铁孵、登錄等流程,
    # User 是 django 為我們已經(jīng)寫好的用戶模型房资,
    # 這里我們通過 ForeignKey 把文章和 User 關(guān)聯(lián)起來蜕劝,
    # 因?yàn)槲覀円?guī)定一篇文章只能有一個作者,
    # 而一個作者可能會寫多篇文章轰异,
    # 因此這是一對多的關(guān)系岖沛,
    # 和 Category 類似。
    author = models.ForeignKey(User)

數(shù)據(jù)庫模型詳解

首先是 Category(分類)和 Tag(標(biāo)簽)類搭独,它們均繼承自 model.Model 類婴削,這是 django 規(guī)定的。它們均有一個 name 屬性牙肝,用來存儲它們的名稱唉俗。由于分類名和標(biāo)簽名一般都是用字符串表示,因此我們使用了 CharField 來指定 name 的數(shù)據(jù)類型配椭,同時 max_length 參數(shù)則指定 name 的最大長度虫溜。除了 CharField ,django 還為我們提供了更多內(nèi)置的數(shù)據(jù)類型股缸,比如時間類型 DateTimeField衡楞、整數(shù)類型 IntegerField 等等。在本教程中我們會教你這些類型的使用方法敦姻,但以后你開發(fā)自己的項(xiàng)目時寺酪,你就需要通過閱讀 [django 的官方文檔關(guān)于字段類型的介紹][1]來了解有哪些數(shù)據(jù)類型以及如何使用它們。
[1]: https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types

Post(文章)類也一樣替劈,必須繼承自 model.Model 類寄雀。文章的數(shù)據(jù)庫表稍微復(fù)雜一點(diǎn),主要是列更多陨献。我們?yōu)樗付诉@些列:

  • title盒犹。這是文章的標(biāo)題,數(shù)據(jù)類型是 CharField眨业,最大長度 max_length = 70急膀。

  • body。文章正文龄捡,我們使用了 TextField卓嫂。比較短的字符串存儲可以使用 CharField,但對于文章的正文來說可能會是一大段文本聘殖,因此使用 TextField 來存儲大段文本晨雳。

  • created_time行瑞、modified_time。這兩個列分表表示了文章的創(chuàng)建時間和最后一次修改時間餐禁,存儲時間的列用 DateTimeField 數(shù)據(jù)類型

  • excerpt血久。文章摘要,可以沒有文章摘要帮非,但默認(rèn)情況下 CharField 要求我們必須存入數(shù)據(jù)氧吐,否則就會報錯。指定 blank=True 后就可以允許空值了末盔。

  • category 和 tags筑舅。這是分類與標(biāo)簽,分類與標(biāo)簽的模型我們已經(jīng)定義在上面陨舱。我們在這里把文章對應(yīng)的數(shù)據(jù)庫表和分類與標(biāo)簽對應(yīng)的表關(guān)聯(lián)起來豁翎,但是關(guān)聯(lián)形式稍微有點(diǎn)不同。我們規(guī)定一篇文章只能對應(yīng)一個分類隅忿,但是一個分類下可以有很多篇文章心剥,所以我們使用的是 ForeignKey,即一對多的關(guān)系背桐。而對于標(biāo)簽來說优烧,一篇文章可以有多個標(biāo)簽,同一個標(biāo)簽下也可能有多篇文章链峭,所以我們使用 ManyToManyField畦娄,表明這是多對多的關(guān)系。同時我們規(guī)定文章可以沒有標(biāo)簽弊仪,因此為標(biāo)簽 tags 指定了 blank=True熙卡。

  • author。文章作者励饵,這里 User 是從 django.contrib.auth.models 導(dǎo)入的驳癌。django.contrib.auth 是 django 內(nèi)置的應(yīng)用,專門用于處理網(wǎng)站用戶的注冊役听、登錄等流程颓鲜,User 是 django 為我們已經(jīng)寫好的用戶模型,這里我們通過 ForeignKey 把文章和 User 關(guān)聯(lián)起來典予,因?yàn)槲覀円?guī)定一篇文章只能有一個作者甜滨,而一個作者可能會寫多篇文章,因此這是一對多的關(guān)系瘤袖,和 Category 類似衣摩。

注:這里我們使用了兩種關(guān)聯(lián)數(shù)據(jù)庫表的形式,一種是 ForeignKey捂敌,它表明一種一對多的關(guān)聯(lián)艾扮。比如這里我們的文章和分類的關(guān)系既琴,一篇文章只能對應(yīng)一個分類,而一個分類下可以有多篇文章栏渺。另外一中是 ManyToManyField,看名字就知道這是一種多對多的關(guān)聯(lián)關(guān)系锐涯,比如這里的文章和標(biāo)簽磕诊,一篇文章可以有多個標(biāo)簽,而一個標(biāo)簽下也可以有多篇文章纹腌。假如你對此有一些困惑霎终,強(qiáng)烈建議閱讀官方文檔對這兩種關(guān)系的說明以及更多官方的例子以加深理解:

django ForeignKey 簡介

django ForeignKey 詳細(xì)示例

django ManyToManyField 簡介

django ManyToManyField 詳細(xì)示例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市升薯,隨后出現(xiàn)的幾起案子莱褒,更是在濱河造成了極大的恐慌,老刑警劉巖涎劈,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件广凸,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛛枚,警方通過查閱死者的電腦和手機(jī)谅海,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹦浦,“玉大人扭吁,你說我怎么就攤上這事∶は猓” “怎么了侥袜?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溉贿。 經(jīng)常有香客問我枫吧,道長,這世上最難降的妖魔是什么宇色? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任由蘑,我火速辦了婚禮,結(jié)果婚禮上代兵,老公的妹妹穿的比我還像新娘尼酿。我一直安慰自己,他們只是感情好植影,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布裳擎。 她就那樣靜靜地躺著,像睡著了一般思币。 火紅的嫁衣襯著肌膚如雪鹿响。 梳的紋絲不亂的頭發(fā)上羡微,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音惶我,去河邊找鬼妈倔。 笑死,一個胖子當(dāng)著我的面吹牛绸贡,可吹牛的內(nèi)容都是我干的盯蝴。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼听怕,長吁一口氣:“原來是場噩夢啊……” “哼捧挺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起尿瞭,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤闽烙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后声搁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黑竞,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年疏旨,在試婚紗的時候發(fā)現(xiàn)自己被綠了摊溶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡充石,死狀恐怖莫换,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情骤铃,我是刑警寧澤拉岁,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站惰爬,受9級特大地震影響喊暖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撕瞧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一陵叽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧丛版,春花似錦巩掺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春独令,著一層夾襖步出監(jiān)牢的瞬間端朵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工燃箭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留冲呢,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓招狸,卻偏偏與公主長得像敬拓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瓢颅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容