
# 存儲
大多數Flask應用都將要跟數據打交道。有很多種不同的方法存儲數據。至于哪種最優,取決于數據的類型。如果你儲存的是關系性數據(比如一個用戶有多個郵件,一個郵件對應一個用戶),關系型數據庫無疑是你的選擇。其他類型的數據也許適合儲存到NoSQL數據庫(比如MongoDB)中。
我不會告訴你如何為你的應用選擇數據庫。如果有人告訴你,NoSQL是你的唯一選擇;那么必然也會有人建議用關系型數據庫處理同樣的問題。對此我唯一需要說的是,如果你不清楚,關系型數據庫(MySQL, PostgreSQL等等)將滿足你絕大部分的需求。
另外,當你使用關系型數據庫,你就能用到SQLAlchemy,而SQLAlchemy用起來真爽。
## SQLAlchemy
SQLAlchemy是一個ORM([對象關系映射](http://zh.wikipedia.org/wiki/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84))。基于對目標數據庫的原生SQL的抽象,它提供了與一長串數據庫引擎的一致的API。這一列表中包括MySQL,PostgreSQL,和SQLite。這使得在你的模型和數據庫間交換數據變得輕松愉快,同時也使得諸如換掉數據庫引擎和遷移數據庫模式等其他事情變得沒那么繁瑣。
存在一個很棒的Flask插件使得在Flask中使用SQLAlchemy更為輕松。它就是Flask-SQLAlchemy。Flask-SQLAlchemy為SQLAlchemy設置了許多合理的配置。它也內置了一些session管理,這樣你就不用在應用代碼里處理這種基礎事務了。
讓我們深入看看一些代碼。我們將先定義一些模型,接著配置下SQLAchemy。這些模型將位于*myapp/models.py*,不過首先我們要在*myapp/\_\_init\_\_.py*定義我們的數據庫。
<em>myapp/\_\_init\_\_.py_</em>
```
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__, instance_relative_config=True)
app.config.from_object('config')
app.config.from_pyfile('config.py')
db = SQLAlchemy(app)
```
我們首先初始化并配置你的Flask應用,然后用它來初始化你的SQLAlchemy數據庫處理程序。我們將為數據庫配置使用一個instance文件夾,所以我們應該在初始化應用時加上`instance_relative_config`選項,然后調用`app.config.from_pyfile`。現在我們可以定義模型了。
_myapp/models.py_
```
from . import db
class Engine(db.Model):
# Columns
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(128))
thrust = db.Column(db.Integer, default=0)
```
`Column`,`Integer`,`String`,`Model`和其他的SQLAlchemy類都可以通過由Flask-SQLAlchemy構造的`db`對象訪問。我們會定義一個儲存我們的太空飛船引擎的當前狀態的模型。每個引擎有一個ID,一個標題和一個推力等級。
我們需要往我們的配置添加一些數據庫信息。我們打算使用一個instance文件夾來避免配置變量被記錄進版本控制系統,所以我們要把它們放入*instance/config.py*。
_instance/config.py_
```
SQLALCHEMY_DATABASE_URI = "postgresql://user:password@localhost/spaceshipDB"
```
> **注意**
> 你的數據庫URI將取決于你選擇的數據庫和它部署的位置。看一下這個相關的SQLAlchemy文檔:
> <http://docs.sqlalchemy.org/en/latest/core/engines.html?highlight=database#database-urls>
## 初始化數據庫
既然數據庫已經配置好了,而模型也定義了,是時候初始化數據庫了。這個步驟從由模型定義中創建數據庫模式開始。
通常這會是非常痛苦的過程。不過幸運的是,SQLAlchemy提供了一個十分酷的工具幫我們完成了所有的瑣事。
讓我們在版本庫的根目錄下打開一個Python終端。
```
$ pwd
/Users/me/Code/myapp
$ workon myapp
(myapp)$ python
Python 2.7.5 (default, Aug 25 2013, 00:04:04)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from myapp import db
>>> db.create_all()
>>>
```
現在,感謝SQLAlchemy,你會發現在你配置的數據庫中,所需的表格已經被創建出來了。
## Alembic遷移工具
數據庫的模式并非亙古不變的。舉個例子,你可能需要在引擎的表里添加一個`last_fired`的項。如果這個表是一張白紙,你只需要更新模型并重新運行`db.create_all()`。然而,如果你在引擎表里記錄了六個月的數據,你肯定不會想要從頭開始。這時候就需要數據庫遷移工具了。
Alembic是專用于SQLAlchemy的數據庫遷移工具。它允許你保持你的數據庫模式的版本歷史,這樣你就可以升級到一個新的模式,或者降級到舊的模式。
Alembic有一個可拓展的新手教程,所以我只會大概地說一下并指出一些需要注意的事項。
通過一個初始化的`alembic init`命令,你將創建一個alembic"遷移環境"。在你的版本庫的根目錄下執行這個命令,你將得到一個叫`alembic`的新文件夾。你的版本庫將看上去就像Alembic教程中的這個例子一樣:
```
myapp/
alembic.ini
alembic/
env.py
README
script.py.mako
versions/
3512b954651e_add_account.py
2b1ae634e5cd_add_order_id.py
3adcc9a56557_rename_username_field.py
myapp/
__init__.py
views.py
models.py
templates/
run.py
config.py
requirements.txt
```
*alembic/*文件夾中包括了在版本間遷移數據的腳本。同時會有一個包括配置信息的*alembic.ini*文件。
> **注意**
> 把*alembic.ini*添加到*.gitignore*中!在那里會有你的數據庫憑證,所以你*不應該*把它留在版本控制中。
> 不過你可以把*alembic/*放進版本控制。它不會包含敏感信息(而且不能從你的源代碼中重新生成),并且在版本控制中保存多個副本可以避免你的電腦發生不測。
當數據庫模式需要發生變化時,我們需要做一系列事情。首先,運行`alembic revision`來生成遷移腳本。在*myapp/alembic/versions/*打開新生成的Python文件并使用Alembic的`op`對象完成`upgrade`和`downgrade`函數。
一旦我們的遷移腳本已經準備就緒,我們只需運行`alembic upgrade head`來遷移我們的數據到最新版本。
> **參見**
> 想知道更多關于配置Alembic,創建你的遷移腳本和運行你的遷移,請看Alembic教程:
> <http://alembic.readthedocs.org/en/latest/tutorial.html>
> **注意**
> 不要忘記設定數據的備份計劃。備份計劃的話題已經超出本書的范圍,但你應該總是要有一個安全和健壯的方式備份你的數據庫。
> **注意**
> Flask在NoSQL上的支持較少,但只要有你選擇的數據庫引擎有對應的Python庫,你就能夠用上它。這里有一些Flask插件,可以給Flask提供NoSQL引擎的支持。
> <http://flask.pocoo.org/extensions/>
## 總結
- 使用SQLAchemy來搭配關系型數據庫。
- 使用Flask-SQLAlchemy來包裝SQLAlchemy。
- Alembic會在數據庫模式改變時幫助你管理數據遷移。
- 你可以用NoSQL搭配Flask,但具體做法取決于具體引擎。
- 記得備份你的數據!