博客最主要的功能就是展現咱們寫的文章,它須要從某個地方獲取博客文章數據才能把文章展現出來,一般來講這個地方就是數據庫。咱們把寫好的文章永久地保存在數據庫裏,當用戶訪問咱們的博客時,Django 就去數據庫裏把這些數據取出來展示給用戶。python
博客的文章應該含有標題、正文、做者、發表時間等數據。一個更加現代化的博客文章還但願它有分類、標籤、評論等。爲了更好地存儲這些數據,咱們須要合理地組織數據庫的表結構。git
咱們的博客初級版本主要包含博客文章,文章會有分類以及標籤。一篇文章只能有一個分類,但能夠打上不少標籤。github
數據庫存儲的數據其實就是表格的形式,例如存儲博客文章的數據庫表長這個樣子:數據庫
文章 id | 標題 | 正文 | 發表時間 | 分類 | 標籤 |
---|---|---|---|---|---|
1 | title 1 | text 1 | 2016-12-23 | Django | Django 學習 |
2 | title 2 | text 2 | 2016-12-24 | Django | Django 學習 |
3 | title 3 | text 3 | 2016-12-26 | Python | Python 學習 |
其中文章 ID 是一個數字,惟一對應着一篇文章。固然還能夠有更多的列以存儲更多相關數據,這只是一個最基本的示例。django
數據庫表設計成這樣其實已經能夠了,可是稍微分析一下咱們就會發現一個問題,這 3 篇文章的分類和標籤都是相同的,這會產生不少重複數據,當數據量很大時就浪費了存儲空間。編程
不一樣的文章可能它們對應的分類或者標籤是相同的,因此咱們把分類和標籤提取出來,作成單獨的數據庫表,再把文章和分類、標籤關聯起來。下面分別是分類和標籤的數據庫表:app
分類 id | 分類名 |
---|---|
1 | Django |
2 | Python |
標籤 id | 標籤名 |
---|---|
1 | Django 學習 |
2 | Python 學習 |
以上是天然語言描述的表格,數據庫也和編程語言同樣,有它本身的一套規定的語法來生成上述的表結構,這樣咱們才能把數據存進去。通常來講這時候咱們應該先去學習數據庫建立表格的語法,再回來寫咱們的 Django 博客代碼了。可是 Django 告訴咱們不用這麼麻煩,它已經幫咱們作了一些事情。Django 把那一套數據庫的語法轉換成了 Python 的語法形式,咱們只要寫 Python 代碼就能夠了,Django 會把 Python 代碼翻譯成對應的數據庫操做語言。用更加專業一點的說法,就是 Django 爲咱們提供了一套 ORM(Object Relational Mapping)系統。編程語言
例如咱們的分類數據庫表,Django 只要求咱們這樣寫:編輯器
blog/models.py from django.db import models class Category(models.Model): name = models.CharField(max_length=100)
Category
就是一個標準的 Python 類,它繼承了 models.Model
類,類名爲 Category
。Category
類有一個屬性 name
,它是 models.CharField
的一個實例。post
這樣,Django 就能夠把這個類翻譯成數據庫的操做語言,在數據庫裏建立一個名爲 category 的表格,這個表格的一個列名爲 name。還有一個列 id,Django 則會自動建立。能夠看出從 Python 代碼翻譯成數據庫語言時其規則就是一個 Python 類對應一個數據庫表格,類名即表名,類的屬性對應着表格的列,屬性名即列名。
咱們須要 3 個表格:文章(Post)、分類(Category)以及標籤(Tag),下面就來分別編寫它們對應的 Python 類。模型的代碼一般寫在相關應用的 models.py 文件裏。已經在代碼中作了詳細的註釋,說明每一句代碼的含義。但若是你在移動端下閱讀不便的話,也能夠跳到代碼後面看正文的裏的講解。
注意:代碼中含有中文註釋,若是你直接 copy 代碼到你的文本編輯器且使用了 Python 2 開發環境的話,會獲得一個編碼錯誤。所以請在文件最開始處加入編碼聲明:# coding: utf-8。
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 的數據類型,CharField 是字符型, CharField 的 max_length 參數指定其最大長度,超過這個長度的分類名就不能被存入數據庫。 固然 Django 還爲咱們提供了多種其它的數據類型,如日期時間類型 DateTimeField、整數類型 IntegerField 等等。 Django 內置的所有類型可查看文檔: https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types """ name = models.CharField(max_length=100) class Tag(models.Model): """ 標籤 Tag 也比較簡單,和 Category 同樣。 再次強調必定要繼承 models.Model 類! """ name = models.CharField(max_length=100) class Post(models.Model): """ 文章的數據庫表稍微複雜一點,主要是涉及的字段更多。 """ # 文章標題 title = models.CharField(max_length=70) # 文章正文,咱們使用了 TextField。 # 存儲比較短的字符串可使用 CharField,但對於文章的正文來講可能會是一大段文本,所以使用 TextField 來存儲大段文本。 body = models.TextField() # 這兩個列分別表示文章的建立時間和最後一次修改時間,存儲時間的字段用 DateTimeField 類型。 created_time = models.DateTimeField() modified_time = models.DateTimeField() # 文章摘要,能夠沒有文章摘要,但默認狀況下 CharField 要求咱們必須存入數據,不然就會報錯。 # 指定 CharField 的 blank=True 參數值後就能夠容許空值了。 excerpt = models.CharField(max_length=200, blank=True) # 這是分類與標籤,分類與標籤的模型咱們已經定義在上面。 # 咱們在這裏把文章對應的數據庫表和分類、標籤對應的數據庫表關聯了起來,可是關聯形式稍微有點不一樣。 # 咱們規定一篇文章只能對應一個分類,可是一個分類下能夠有多篇文章,因此咱們使用的是 ForeignKey,即一對多的關聯關係。 # 而對於標籤來講,一篇文章能夠有多個標籤,同一個標籤下也可能有多篇文章,因此咱們使用 ManyToManyField,代表這是多對多的關聯關係。 # 同時咱們規定文章能夠沒有標籤,所以爲標籤 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 導入的。 # django.contrib.auth 是 Django 內置的應用,專門用於處理網站用戶的註冊、登陸等流程,User 是 Django 爲咱們已經寫好的用戶模型。 # 這裏咱們經過 ForeignKey 把文章和 User 關聯了起來。 # 由於咱們規定一篇文章只能有一個做者,而一個做者可能會寫多篇文章,所以這是一對多的關聯關係,和 Category 相似。 author = models.ForeignKey(User)
首先是 Category
和 Tag
類,它們均繼承自 model.Model
類,這是 Django 規定的。Category
和 Tag
類均有一個 name
屬性,用來存儲它們的名稱。因爲分類名和標籤名通常都是用字符串表示,所以咱們使用了 CharField
來指定 name
的數據類型,同時 max_length
參數則指定 name
容許的最大長度,超過該長度的字符串將不容許存入數據庫。除了 CharField
,Django 還爲咱們提供了更多內置的數據類型,好比時間類型 DateTimeField
、整數類型 IntegerField
等等。
在本教程中咱們會教你這些類型的使用方法,但之後你開發本身的項目時,你就須要經過閱讀Django 官方文檔 關於字段類型的介紹 來了解有哪些數據類型可使用以及如何使用它們。
Post
類也同樣,必須繼承自 model.Model
類。文章的數據庫表稍微複雜一點,主要是列更多,咱們指定了這些列:
title
。這是文章的標題,數據類型是 CharField
,容許的最大長度 max_length = 70
。
body
。文章正文,咱們使用了 TextField
。比較短的字符串存儲可使用 CharField
,但對於文章的正文來講可能會是一大段文本,所以使用 TextField
來存儲大段文本。
created_time
、modified_time
。這兩個列分別表示文章的建立時間和最後一次修改時間,存儲時間的列用 DateTimeField
數據類型。
excerpt
。文章摘要,能夠沒有文章摘要,但默認狀況下 CharField
要求咱們必須存入數據,不然就會報錯。指定 CharField
的 blank=True
參數值後就能夠容許空值了。
category
和 tags
。這是分類與標籤,分類與標籤的模型咱們已經定義在上面。咱們把文章對應的數據庫表和分類、標籤對應的數據庫表關聯了起來,可是關聯形式稍微有點不一樣。咱們規定一篇文章只能對應一個分類,可是一個分類下能夠有多篇文章,因此咱們使用的是 ForeignKey
,即一對多的關聯關係。而對於標籤來講,一篇文章能夠有多個標籤,同一個標籤下也可能有多篇文章,因此咱們使用 ManyToManyField
,代表這是多對多的關聯關係。同時咱們規定文章能夠沒有標籤,所以爲標籤 tags 指定了 blank=True
。
author
。文章做者,這裏 User
是從 django.contrib.auth.models 導入的。django.contrib.auth 是 Django 內置的應用,專門用於處理網站用戶的註冊、登陸等流程。其中 User
是 Django 爲咱們已經寫好的用戶模型,和咱們本身編寫的 Category
等類是同樣的。這裏咱們經過 ForeignKey
把文章和 User
關聯了起來,由於咱們規定一篇文章只能有一個做者,而一個做者可能會寫多篇文章,所以這是一對多的關聯關係,和 Category
相似。
咱們分別使用了兩種關聯數據庫表的形式:ForeignKey 和 ManyToManyField。
ForeignKey
代表一種一對多的關聯關係。好比這裏咱們的文章和分類的關係,一篇文章只能對應一個分類,而一個分類下能夠有多篇文章。反應到數據庫表格中,它們的實際存儲狀況是這樣的:
文章 ID | 標題 | 正文 | 分類 ID |
---|---|---|---|
1 | title 1 | body 1 | 1 |
2 | title 2 | body 2 | 1 |
3 | title 3 | body 3 | 1 |
4 | title 4 | body 4 | 2 |
分類 ID | 分類名 | |
---|---|---|
1 | Django | |
2 | Python |
能夠看到文章和分類其實是經過文章數據庫表中 分類 ID 這一列關聯的。當要查詢文章屬於哪個分類時,只須要查看其對應的分類 ID 是多少,而後根據這個分類 ID 就能夠從分類數據庫表中找到該分類的數據。例如這裏文章 一、二、3 對應的分類 ID 均爲 1,而分類 ID 爲 1 的分類名爲 Django,因此文章 一、二、3 屬於分類 Django。同理文章 4 屬於分類 Python。
反之,要查詢某個分類下有哪些文章,只須要查看對應該分類 ID 的文章有哪些便可。例如這裏 Django 的分類 ID 爲 1,而對應分類 ID 爲 1 的文章有文章 一、二、3,因此分類 Django 下有 3 篇文章。
但願這個例子能幫助你加深對多對一關係,以及它們在數據庫中是如何被關聯的理解,更多的例子請看文末給出的 Django 官方參考資料。
ManyToManyField
代表一種多對多的關聯關係,好比這裏的文章和標籤,一篇文章能夠有多個標籤,而一個標籤下也能夠有多篇文章。反應到數據庫表格中,它們的實際存儲狀況是這樣的:
文章 ID | 標題 | 正文 |
---|---|---|
1 | title 1 | body 1 |
2 | title 2 | body 2 |
3 | title 3 | body 3 |
4 | title 4 | body 4 |
標籤 ID | 標籤名 |
---|---|
1 | Django 學習 |
2 | Python 學習 |
文章 ID | 標籤 ID |
---|---|
1 | 1 |
1 | 2 |
2 | 1 |
3 | 2 |
多對多的關係沒法再像一對多的關係中的例子同樣在文章數據庫表加一列 分類 ID 來關聯了,所以須要額外建一張表來記錄文章和標籤之間的關聯。例如文章 ID 爲 1 的文章,既對應着 標籤 ID 爲 1 的標籤,也對應着 標籤 ID 爲 2 的標籤,即文章 1 既屬於標籤 1:Django 學習,也屬於標籤 2:Python 學習。
反之,標籤 ID 爲 1 的標籤,既對應着 文章 ID 爲 1 的文章,也對應着 文章 ID 爲 2 的文章,即標籤 1:Django 學習下有兩篇文章。
但願這個例子能幫助你加深對多對多關係,以及它們在數據庫中是如何被關聯的理解,更多的例子請看文末給出的 Django 官方參考資料。
假如你對多對一關係和多對多關係還存在一些困惑,強烈建議閱讀官方文檔對這兩種關係的說明以及更多官方的例子以加深理解:
本章節的代碼位於:Step3: blog models。
若是遇到問題,請經過下面的方式尋求幫助。
在 建立 Django 博客的數據庫模型 - 追夢人物的博客 的評論區留言。
將問題的詳細描述經過郵件發送到 djangostudyteam@163.com,通常會在 24 小時內回覆。
更多Django 教程,請訪問 追夢人物的博客。