5. 讓 django 完成翻譯——遷移數據庫模型

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

這是 Django 博客教程的第 5 篇,在閱讀此篇教程以前,請確保你已閱讀 Django 博客教程的前 4 篇:
1. Django 博客教程:前言
2. 搭建開發(fā)環(huán)境
3. 建立我們的 django 博客應用
4. 創(chuàng)建 django 博客的數據庫模型

上一篇教程中我們完成了數據庫模型的代碼,但是那還只是 Python 代碼而已,我們還沒有讓 django 把它翻譯成數據庫語言,因此實際上這些數據庫表格沒有真正地創(chuàng)建。

為了讓 django 完成翻譯,幫我們創(chuàng)建好這些數據庫表,我們再一次請出我的工程管理助手 manage.py。進入虛擬環(huán)境,切換到 manage.py 文件所在的目錄下,分別運行 python manage.py makemigrationspython manage.py migrate 命令:

C:\WINDOWS\system32>C:\Users\yangxg\Envs\blogproject_env\Scripts\activate

(blogproject_env) C:\WINDOWS\system32>cd C:\Users\yangxg\Workspace\blogproject

(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py makemigrations
Migrations for 'blog':
  blog\migrations\0001_initial.py:
    - Create model Category
    - Create model Post
    - Create model Tag
    - Add field tags to post
(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK

可以看到,當我們執(zhí)行了 python manage.py makemigrations 后,django 在 blog 應用的 migrations 目錄下生成了一個 0001_initial.py 文件,這個文件是 django 用來記錄我們對模型做了哪些修改的文件。目前來說,我們在 models.py 文件里創(chuàng)建了 3 個模型類,django 把這些變化記錄在了 0001_initial.py 里。但此時只是告訴了 django 我們做了哪些改變,為了讓 django 真正地為我們創(chuàng)建數據庫表,接下來又執(zhí)行了 python manage.py migrate 命令。django 通過檢測應用中 migrations 目錄下的文件,得知我們對數據庫做了哪些操作,然后它把這些操作翻譯成數據庫語言,從而把這些操作應用于真正的數據庫里。你可以看到命令的輸出除了 Applying blog.0001_initial... OK 外,django 還對其他文件做了操作。這是因為除了我們自己建立的 blog 應用外,django 自身還內置了很多應用,這些應用自己也是需要數據的??梢栽?settings.py 的 INSTALLED_APP 設置里看到這些應用:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

當然我們目前不必關心這些。

寫給了解數據庫語言的人:你可以運行下面的命令看看 django 究竟為我們做了什么:

python manage.py sqlmigrate blog 0001

你將看到輸出的經 django 翻譯后的數據庫表創(chuàng)建語句,這有助于你理解 django 的 ORM 的工作機制。

使用 django 的方式從數據庫里獲取數據

數據庫最主要的操作就是往里面存入數據、從中取出數據、修改已保存的數據和刪除不再需要的數據。和創(chuàng)建數據庫表一樣,django 為這些操作提供了一整套方法,從而把我們從數據庫中解放出來。我們不用學習如何利用數據庫語言去完成這些操作,只要簡單地調用幾個 python 函數就可以滿足我們的需求。

先在命令行中來探索一下這些函數,感受一下如何使用 django 的方式來操作數據庫。在 manage.py 所在目錄下運行命令:

(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py shell
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

這打開了一個交互式命令行。

首先我們來創(chuàng)建一個分類和一個標簽:

>>> from blog.models import Category, Tag, Post
>>> c = Category(name='category test')
>>> c.save()
>>> t = Tag(name='tag test')
>>> t.save()

我們首先導入 3 個我們之前寫好的模型類,然后實例化了一個 Category 類和一個 Tag 類,為他們的屬性 name 賦了值。為了讓 django 幫我們把這些數據保存進數據庫,調用實例的 save() 方法即可。

再創(chuàng)建一篇文章試試,但創(chuàng)建文章之前,我們需要先創(chuàng)建一個 User,用于指定文章的作者,創(chuàng)建 User 的命令 django 已經幫我們寫好了,依然是通過 manage.py 來運行。首先按住 Ctrl + c 退出命令交互欄,運行下面的命令并根據提示創(chuàng)建用戶:

(blogproject_env) C:\Users\yangxg\Workspace\blogproject>python manage.py createsuperuser
Username (leave blank to use 'zmrenwu@163.com'): myuser
Email address: a@aa.com
Password:
Password (again):
Superuser created successfully.

運行 python manage.py createsuperuser 開始創(chuàng)建用戶,之后會提示你輸入用戶名、郵箱、密碼和確認密碼,按照提示輸入即可。注意一點的是密碼輸入過程中不會有任何字符顯示,不要誤以為你的鍵盤出問題了。最后出現 Superuser created successfully. 說明用戶創(chuàng)建成功了。

再次進入 Python 命令交互欄,開始創(chuàng)建文章:

>>> from blog.models import Category, Tag, Post
>>> from django.utils import timezone
>>> from django.contrib.auth.models import User

>>> user = User.objects.get(username='myuser')
>>> c = Category.objects.get(name='category test')

>>> p = Post(title='title test', body='body test', created_time=timezone.now(), modified_time=timezone.now(), category=c, author=user)
>>> p.save()

由于我們重啟了 shell,因此我們重新導入了 Category, Tag, Post 以及 User,我們還導入了一個 django 提供的輔助模塊 timezone,這是因為我們需要調用它的 now() 方法為 created_time 和 modified_time 指定時間。然后我們根據用戶名和分類名,通過 get 方法取出了存在數據庫中的 User 和 Category(取數據將在下面介紹)。此外還指定 title,body 的值,并把它和前面創(chuàng)建的 category c 關聯了起來,只有允許為空 excerpt、tags 我們就沒有為他們指定值了。

數據已經存入數據庫了,現在要把它們取出來看看:

>>> Category.objects.all()
<QuerySet [<Category: Category object>]>
>>> Tag.objects.all()
<QuerySet [<Tag: Tag object>]>
>>> Post.objects.all()
<QuerySet [<Post: Post object>]>
>>>

objects 是我們的模型管理器,它為我們提供一系列從數據庫中取數據方法,這里我們使用了 all() 方法,表示我們要把對應的數據全部取出來。可以看到 all() 方法都返回了數據,這些數據應該是我們之前存進去的,但是顯示的字符串有點奇怪,讓人看不懂。為了讓顯示出來的數據更加人性化一點,我們分別為三個模型增加一個 __str__() 方法:

from django.utils.six import python_2_unicode_compatible

@python_2_unicode_compatible
class Category(models.Model):
    ...

    def __str__(self):
        # python_2_unicode_compatible 裝飾器用于兼容 Python2
        return self.name
    
@python_2_unicode_compatible
class Tag(models.Model):
    ...

    def __str__(self):
        # python_2_unicode_compatible 裝飾器用于兼容 Python2
        return self.name
    
@python_2_unicode_compatible
class Post(models.Model):
    ...
    
    def __str__(self):
        # python_2_unicode_compatible 裝飾器用于兼容 Python2
        return self.title

定義好 __str__() 方法后,解釋器顯示的內容將會是由 __str__() 方法返回的內容,這里 Category 返回分類名 name,Tag 返回標簽名,而 Post 返回它的 title。

先按 Ctrl + C 退出 shell,再重新運行 python manage.py shell 進入 shell。

>>> from blog.models import Category, Tag, Post
>>> Category.objects.all()
<QuerySet [<Category: category test>]>

>>> Tag.objects.all()
<QuerySet [<Tag: tag test>]>

>>> Post.objects.all()
<QuerySet [<Post: title test>]>

可以看到返回的是我們之前存入的數據。此外我們在創(chuàng)建文章時提到了通過 get 方法來獲取數據,這里 all 方法和 get 方法的區(qū)別是,all 返回全部數據,是一個列表,而 get 返回一條記錄數據。

嘗試修改數據:

>>> c = Category.objects.get(name='category test')
>>> c.name = 'category test new'
>>> c.save()
>>> Category.objects.all()
<QuerySet [<Category: test category new>]>

首先通過 get 方法根據分類名 name 獲取到分類,修改它的 name 屬性為新的值 category test new,然后調用 save 方法把修改保存到數據庫,之后可以看到數據庫返回的數據已經是修改后的值了。Tag、Post 的修改也一樣。

刪除掉數據:

>>> p = Post.objects.get(title='title test')
>>> p
<Post: title test>
>>> p.delete()
(1, {'blog.Post_tags': 0, 'blog.Post': 1})
>>> Post.objects.all()
<QuerySet []>

先根據標題 title 從數據庫中取出 Post,保存在變量 p 中,然后調用它的 delete 方法,最后看到 Post.objects.all() 返回了一個空的 QuerySet(類似于一個列表),表明數據庫中沒有 Post,Post 已經被刪除了。

這就是 django 對數據庫增、刪、改、查的操作。除了上述演示的方法外,django 還為我們提供了大量其它的方法,這些方法有一部分會在教程中使用,用到時我會講解它們的用法。但以后你開發(fā)自己的項目時,你就需要通過閱讀 django 的官方文檔 來了解有哪些方法已經如何使用它們。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,578評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 99,701評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,691評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,974評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,694評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,026評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,015評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,193評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 49,719評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,442評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,668評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,151評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,846評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,255評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,592評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,394評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容