4 - 讓 Django 完成翻譯:遷移數據庫

咱們已經編寫了博客數據庫模型的代碼,但那還只是 Python 代碼而已,Django 尚未把它翻譯成數據庫語言,所以實際上這些數據庫表尚未真正的在數據庫中建立。javascript

遷移數據庫

爲了讓 Django 完成翻譯,建立好這些數據庫表,咱們再一次請出個人工程管理助手 manage.py。激活虛擬環境,切換到 manage.py 文件所在的目錄下,分別運行 python manage.py makemigrationspython manage.py migrate 命令:java

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複製代碼

注意:若是代碼中含有中文註釋,且你使用的是 Python 2 開發環境的話,會獲得一個編碼錯誤。所以請在含有中文註釋的文件最開始處加入編碼聲明:# coding: utf-8。python

當咱們執行了 python manage.py makemigrations 後,Django 在 blog 應用的 migrations\ 目錄下生成了一個 0001_initial.py 文件,這個文件是 Django 用來記錄咱們對模型作了哪些修改的文件。目前來講,咱們在 models.py 文件裏建立了 3 個模型類,Django 把這些變化記錄在了 0001_initial.py 裏。git

不過此時還只是告訴了 Django 咱們作了哪些改變,爲了讓 Django 真正地爲咱們建立數據庫表,接下來又執行了 python manage.py migrate 命令。Django 經過檢測應用中 migrations\ 目錄下的文件,得知咱們對數據庫作了哪些操做,而後它把這些操做翻譯成數據庫操做語言,從而把這些操做做用於真正的數據庫。github

你能夠看到命令的輸出除了 Applying blog.0001_initial... OK 外,Django 還對其它文件作了操做。這是由於除了咱們本身創建的 blog 應用外,Django 自身還內置了不少應用,這些應用自己也是須要存儲數據的。能夠在 settings.py 的 INSTALLED_APP 設置裏看到這些應用,固然咱們目前沒必要關心這些。sql

blogproject/settings.py

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

對於瞭解數據庫語言的人,你能夠運行下面的命令看看 Django 究竟爲咱們作了什麼:shell

python manage.py sqlmigrate blog 0001複製代碼

你將看到輸出了經 Django 翻譯後的數據庫表建立語句,這有助於你理解 Django ORM 的工做機制。數據庫

選擇數據庫版本

咱們沒有安裝任何的數據庫軟件,Django 就幫咱們遷移了數據庫。這是由於咱們使用了 Python 內置的 SQLite3 數據庫。django

SQLite3 是一個十分輕巧的數據庫,它僅有一個文件。你能夠看一到項目根目錄下多出了一個 db.sqlite3 的文件,這就是 SQLite3 數據庫文件,Django 博客的數據都會保存在這個數據庫文件裏。session

Django 在 settings.py 裏爲咱們作了一些默認的數據庫配置:

blogproject/settings.py

## 其它配置選項...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
## 其它配置選項...複製代碼

能夠看到默認的數據庫引擎就是使用的 SQLite3。

固然一些人傾向於使用 MySQL 等大型數據庫,至於 Django 如何配置 MySQL 這裏就不贅述了,你能夠自行使用搜索引擎或者查閱 Django 的官方文檔解決。對於一個小型博客而言,SQLite3 數據庫足以勝任。

用 Django 的方式操做數據庫

數據庫最主要的操做就是往裏面存入數據、從中取出數據、修改已保存的數據和刪除再也不須要的數據。和建立數據庫表同樣,Django 爲這些操做提供了一整套方法,從而把咱們從數據庫語言中解放出來。咱們不用學習如何利用數據庫語言去完成這些操做,只要簡單地調用幾個 Python 函數就能夠知足咱們的需求。

存數據

先在命令行中來探索一下這些函數,感覺一下如何用 Django 的方式來操做數據庫。在 manage.py 所在目錄下運行 python manage.py shell 命令:

(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)
>>>複製代碼

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

首先咱們來建立一個分類和一個標籤:

>>> 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 方法便可。

再建立一篇文章試試,但建立文章以前,咱們須要先建立一個 User,用於指定文章的做者。建立 User 的命令 Django 已經幫咱們寫好了,依然是經過 manage.py 來運行。首先按住 Ctrl + c 退出命令交互欄(一次退不出就連續多按幾回),運行 python manage.py createsuperuser 命令並根據提示建立用戶:

(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 開始建立用戶,以後會提示你輸入用戶名、郵箱、密碼和確認密碼,按照提示輸入便可。注意一點的是密碼輸入過程當中不會有任何字符顯示,不要誤覺得你的鍵盤出問題了,正常輸入便可。最後出現 Superuser created successfully. 說明用戶建立成功了。

再次運行 python manage.py shell 進入 Python 命令交互欄,開始建立文章:

>>> 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,所以須要從新導入了 CategoryTagPost 以及 User。咱們還導入了一個 Django 提供的輔助模塊 timezone,這是由於咱們須要調用它的 now() 方法爲 created_timemodified_time 指定時間,容易理解 now 方法返回當前時間。而後咱們根據用戶名和分類名,經過 get 方法取出了存在數據庫中的 UserCategory(取數據的方法將在下面介紹)。接着咱們爲文章指定了 titlebodycreated_timemodified_time值,並把它和前面建立的 Category 以及 User 關聯了起來。容許爲空 excerpttags 咱們就沒有爲它們指定值了。

注意:咱們這裏使用 get 方法根據 Categoryname 屬性的值獲取分類的一條記錄。Category.objects.get(name='category test') 的含義是從數據庫中取出 name 的值爲 category test 的分類記錄。確保數據庫中只有一條值爲 category test 的記錄,不然 get 方法將返回一個 MultipleObjectsReturned 異常。若是你不當心已經存了多條記錄,請刪掉多餘的記錄。如何刪除數據請看下文。

取數據

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

>>> Category.objects.all()
<QuerySet [<Category: Category object>]>
>>> Tag.objects.all()
<QuerySet [<Tag: Tag object>]>
>>> Post.objects.all()
<QuerySet [<Post: Post object>]>
>>>複製代碼

objects 是咱們的模型管理器,它爲咱們提供一系列從數據庫中取數據方法,這裏咱們使用了 all 方法,表示咱們要把對應的數據所有取出來。能夠看到 all 方法都返回了數據,這些數據應該是咱們以前存進去的,可是顯示的字符串有點奇怪,沒法看出到底是不是咱們以前存入的數據。爲了讓顯示出來的數據更加人性化一點,咱們爲 3 個模型分別增長一個 __str__ 方法:

blog/models.py

from django.utils.six import python_2_unicode_compatible

# python_2_unicode_compatible 裝飾器用於兼容 Python2
@python_2_unicode_compatible
class Category(models.Model):
    ...

    def __str__(self):
        return self.name

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

    def __str__(self):
        return self.name

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

    def __str__(self):
        return self.title複製代碼

定義好 __str__ 方法後,解釋器顯示的內容將會是 __str__ 方法返回的內容。這裏 Category 返回分類名 nameTag 返回標籤名,而 Post 返回它的 title

python_2_unicode_compatible 裝飾器用於兼容 Python2。若是你使用的 Python3 開發環境,去掉這個裝飾器不會有任何影響。若是你使用的 Python2 開發環境,而又不想使用這個裝飾器,則將 __str__ 方法改成 __unicode__ 方法便可。

先按 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>]>

>>> Post.objects.get(title='title test')
<Post: title test>複製代碼

能夠看到返回的是咱們以前存入的數據。

此外咱們在建立文章時提到了經過 get 方法來獲取數據,這裏 all 方法和 get 方法的區別是:all 方法返回所有數據,是一個相似於列表的數據結構(QuerySet);而 get 返回一條記錄數據,若有多條記錄或者沒有記錄,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 獲取值爲 category test 到分類,修改它的 name 屬性爲新的值 category test new,而後調用 save 方法把修改保存到數據庫,以後能夠看到數據庫返回的數據已是修改後的值了。TagPost 的修改也同樣。

刪數據

刪除掉數據:

>>> 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 還爲咱們提供了大量其它的方法,這些方法有一部分會在教程中使用,用到時我會講解它們的用法。但之後你開發本身的項目時,你就須要經過閱讀 Django 的官方文檔 來了解有哪些方法可用以及如何使用它們。

總結

本章節的代碼位於:Step4: make migrations and migrate

若是遇到問題,請經過下面的方式尋求幫助。

相關文章
相關標籤/搜索