本教程內(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)系的說明以及更多官方的例子以加深理解: