天天看點

Django 部落格開發教程 3 - 建立 Django 部落格的資料庫模型

部落格最主要的功能就是展示我們寫的文章,它需要從某個地方擷取部落格文章資料才能把文章展示出來,通常來說這個地方就是資料庫。我們把寫好的文章永久地儲存在資料庫裡,當使用者通路我們的部落格時,django 就去資料庫裡把這些資料取出來展現給使用者。

部落格的文章應該含有标題、正文、作者、發表時間等資料。一個更加現代化的部落格文章還希望它有分類、标簽、評論等。為了更好地存儲這些資料,我們需要合理地組織資料庫的表結構。

我們的部落格初級版本主要包含部落格文章,文章會有分類以及标簽。一篇文章隻能有一個分類,但可以打上很多标簽。

資料庫存儲的資料其實就是表格的形式,例如存儲部落格文章的資料庫表長這個樣子:

文章 id

标題

正文

發表時間

分類

标簽

1

title 1

text 1

2016-12-23

django

django 學習

2

title 2

text 2

2016-12-24

3

title 3

text 3

2016-12-26

python

python 學習

其中文章 id 是一個數字,唯一對應着一篇文章。當然還可以有更多的列以存儲更多相關資料,這隻是一個最基本的示例。

資料庫表設計成這樣其實已經可以了,但是稍微分析一下我們就會發現一個問題,這 3 篇文章的分類和标簽都是相同的,這會産生很多重複資料,當資料量很大時就浪費了存儲空間。

不同的文章可能它們對應的分類或者标簽是相同的,是以我們把分類和标簽提取出來,做成單獨的資料庫表,再把文章和分類、标簽關聯起來。下面分别是分類和标簽的資料庫表:

分類 id

分類名

标簽 id

标簽名

以上是自然語言描述的表格,資料庫也和程式設計語言一樣,有它自己的一套規定的文法來生成上述的表結構,這樣我們才能把資料存進去。一般來說這時候我們應該先去學習資料庫建立表格的文法,再回來寫我們的 django 部落格代碼了。但是 django 告訴我們不用這麼麻煩,它已經幫我們做了一些事情。django 把那一套資料庫的文法轉換成了 python 的文法形式,我們隻要寫 python 代碼就可以了,django 會把 python 代碼翻譯成對應的資料庫操作語言。用更加專業一點的說法,就是 django 為我們提供了一套 orm(object relational mapping)系統。

例如我們的分類資料庫表,django 隻要求我們這樣寫:

<code>category</code> 就是一個标準的 python 類,它繼承了 <code>models.model</code> 類,類名為 <code>category</code> 。<code>category</code> 類有一個屬性 <code>name</code>,它是 <code>models.charfield</code> 的一個執行個體。

這樣,django 就可以把這個類翻譯成資料庫的操作語言,在資料庫裡建立一個名為 category 的表格,這個表格的一個列名為 name。還有一個列 id,django 則會自動建立。可以看出從 python 代碼翻譯成資料庫語言時其規則就是一個 python 類對應一個資料庫表格,類名即表名,類的屬性對應着表格的列,屬性名即列名。

我們需要 3 個表格:文章(post)、分類(category)以及标簽(tag),下面就來分别編寫它們對應的 python 類。模型的代碼通常寫在相關應用的 models.py 檔案裡。已經在代碼中做了詳細的注釋,說明每一句代碼的含義。但如果你在移動端下閱讀不便的話,也可以跳到代碼後面看正文的裡的講解。

注意:代碼中含有中文注釋,如果你直接 copy 代碼到你的文本編輯器且使用了 python 2 開發環境的話,會得到一個編碼錯誤。是以請在檔案最開始處加入編碼聲明:# coding: utf-8。

首先是 <code>category</code> 和 <code>tag</code> 類,它們均繼承自 <code>model.model</code> 類,這是 django 規定的。<code>category</code> 和 <code>tag</code> 類均有一個<code>name</code> 屬性,用來存儲它們的名稱。由于分類名和标簽名一般都是用字元串表示,是以我們使用了 <code>charfield</code> 來指定 <code>name</code> 的資料類型,同時 <code>max_length</code> 參數則指定 <code>name</code> 允許的最大長度,超過該長度的字元串将不允許存入資料庫。除了 <code>charfield</code> ,django 還為我們提供了更多内置的資料類型,比如時間類型 <code>datetimefield</code>、整數類型 <code>integerfield</code> 等等。

<code>post</code> 類也一樣,必須繼承自 <code>model.model</code> 類。文章的資料庫表稍微複雜一點,主要是列更多,我們指定了這些列:

<code>title</code>。這是文章的标題,資料類型是 <code>charfield</code>,允許的最大長度 <code>max_length = 70</code>。

<code>body</code>。文章正文,我們使用了 <code>textfield</code>。比較短的字元串存儲可以使用 <code>charfield</code>,但對于文章的正文來說可能會是一大段文本,是以使用 <code>textfield</code> 來存儲大段文本。

<code>created_time</code>、<code>modified_time</code>。這兩個列分别表示文章的建立時間和最後一次修改時間,存儲時間的列用 <code>datetimefield</code> 資料類型。

<code>excerpt</code>。文章摘要,可以沒有文章摘要,但預設情況下 <code>charfield</code> 要求我們必須存入資料,否則就會報錯。指定 <code>charfield</code> 的 <code>blank=true</code> 參數值後就可以允許空值了。

<code>category</code> 和 <code>tags</code>。這是分類與标簽,分類與标簽的模型我們已經定義在上面。我們把文章對應的資料庫表和分類、标簽對應的資料庫表關聯了起來,但是關聯形式稍微有點不同。我們規定一篇文章隻能對應一個分類,但是一個分類下可以有多篇文章,是以我們使用的是 <code>foreignkey</code>,即一對多的關聯關系。而對于标簽來說,一篇文章可以有多個标簽,同一個标簽下也可能有多篇文章,是以我們使用 <code>manytomanyfield</code>,表明這是多對多的關聯關系。同時我們規定文章可以沒有标簽,是以為标簽 tags 指定了 <code>blank=true</code>。

<code>author</code>。文章作者,這裡 <code>user</code> 是從 django.contrib.auth.models 導入的。django.contrib.auth 是 django 内置的應用,專門用于處理網站使用者的注冊、登入等流程。其中 <code>user</code> 是 django 為我們已經寫好的使用者模型,和我們自己編寫的 <code>category</code> 等類是一樣的。這裡我們通過 <code>foreignkey</code> 把文章和 <code>user</code>關聯了起來,因為我們規定一篇文章隻能有一個作者,而一個作者可能會寫多篇文章,是以這是一對多的關聯關系,和 <code>category</code> 類似。

我們分别使用了兩種關聯資料庫表的形式:foreignkey 和 manytomanyfield。

<code>foreignkey</code> 表明一種一對多的關聯關系。比如這裡我們的文章和分類的關系,一篇文章隻能對應一個分類,而一個分類下可以有多篇文章。反應到資料庫表格中,它們的實際存儲情況是這樣的:

body 1

body 2

body 3

4

title 4

body 4

可以看到文章和分類實際上是通過文章資料庫表中 分類 id 這一列關聯的。當要查詢文章屬于哪一個分類時,隻需要檢視其對應的分類 id 是多少,然後根據這個分類 id 就可以從分類資料庫表中找到該分類的資料。例如這裡文章 1、2、3 對應的分類 id 均為 1,而分類 id 為 1 的分類名為 django,是以文章 1、2、3 屬于分類 django。同理文章 4 屬于分類 python。

反之,要查詢某個分類下有哪些文章,隻需要檢視對應該分類 id 的文章有哪些即可。例如這裡 django 的分類 id 為 1,而對應分類 id 為 1 的文章有文章 1、2、3,是以分類 django 下有 3 篇文章。

希望這個例子能幫助你加深對多對一關系,以及它們在資料庫中是如何被關聯的了解,更多的例子請看文末給出的 django 官方參考資料。

<code>manytomanyfield</code> 表明一種多對多的關聯關系,比如這裡的文章和标簽,一篇文章可以有多個标簽,而一個标簽下也可以有多篇文章。反應到資料庫表格中,它們的實際存儲情況是這樣的:

多對多的關系無法再像一對多的關系中的例子一樣在文章資料庫表加一列 分類 id 來關聯了,是以需要額外建一張表來記錄文章和标簽之間的關聯。例如文章 id 為 1 的文章,既對應着 标簽 id 為 1 的标簽,也對應着 标簽 id 為 2 的标簽,即文章 1 既屬于标簽 1:django 學習,也屬于标簽 2:python 學習。

反之,标簽 id 為 1 的标簽,既對應着 文章 id 為 1 的文章,也對應着 文章 id 為 2 的文章,即标簽 1:django 學習下有兩篇文章。

希望這個例子能幫助你加深對多對多關系,以及它們在資料庫中是如何被關聯的了解,更多的例子請看文末給出的 django 官方參考資料。

假如你對多對一關系和多對多關系還存在一些困惑,強烈建議閱讀官方文檔對這兩種關系的說明以及更多官方的例子以加深了解:

<a href="https://docs.djangoproject.com/en/1.10/topics/db/models/#relationships">django foreignkey 簡介</a>

<a href="https://docs.djangoproject.com/en/1.10/topics/db/examples/many_to_one/">django foreignkey 詳細示例</a>

<a href="https://docs.djangoproject.com/en/1.10/topics/db/models/#many-to-many-relationships">django manytomanyfield 簡介</a>

<a href="https://docs.djangoproject.com/en/1.10/topics/db/examples/many_to_many/">django manytomanyfield 詳細示例</a>

如果遇到問題,請通過下面的方式尋求幫助。

将問題的較長的描述通過郵件發送到 [email protected],一般會在 24 小時内回複。