Flask 環境配置
你的應用程式可能需要大量的軟體包才能正常的工作。如果都不需要 Flask 包的話,你有可能讀錯了教程。當應用程式啟動並執行時候,你的應用程式的 環境 基本上是所有一切事情的根基。我們是幸運的,因為有許多方式使得我們能夠輕鬆地管理我們的環境。
使用 virtualenv 管理你的環境
virtualenv 是用於在所謂 虛擬環境 中隔離你的應用程式的一個工具。一個虛擬環境是包含了你的應用依賴的軟體的一個目錄。一個虛擬環境也能夠改變你的環境變數以維持你的開發環境包含的環境變數。不用下載包,像 Flask, 到你系統級或者使用者級的包目錄,我們可以下載它們到一個獨立的並且只為我們應用使用的目錄。這就可以很容易地指定使用的 Python 的版本以及每一個項目依賴的包。
Virtualenv 也可以讓你在不同的項目中使用相同的包的不同版本。這種靈活性可能是十分重要的,如果你正使用一箇舊的系統並且它的上面有幾個項目需要不同的版本。
當使用 virtualenv 的時候,你通常只需要安裝幾個的 Python 包在你的系統上。其中一個就是 virtualenv 本身。你可以使用 Pip 來安裝 virtualenv 包。
一旦在你的系統上安裝了 virtualenv,你可以開始建立虛擬環境。前往你項目所在的目錄並且運行 virtualenv 命令。它需要一個參數,這個參數就是虛擬環境的目標目錄。下面展示了它大概的樣子。
$ virtualenv venvNew python executable in venv/bin/pythonInstalling Setuptools...........[...].....done.Installing Pip..................[...].....done.
virtualenv 建立一個新的目錄,依賴包將會安裝到這個目錄中。
一旦新的虛擬環境已經建立,你必須啟用它,通過發動建立在虛擬環境裡的 bin/activate 指令碼。
$ which python/usr/local/bin/python$ source venv/bin/activate(venv)$ which python/Users/robert/Code/myapp/venv/bin/python
bin/activate 指令碼對你的 shell 環境變數進行一些改變以致一切都指向新的虛擬環境而不是全域系統。你可以在上面的代碼塊中看到效果。啟用後,python 命令指向虛擬環境的中 Python 的 bin 目錄。當虛擬環境啟用後,使用 Pip 安裝的依賴包會被下載到虛擬環境中而不是全域系統。
你可能會注意到 shell 中的提示符也已經改變了。virtualenv 預先設定目前啟用虛擬環境的名稱,因此你會知道你不是在全域系統上工作。
你可以通過運行 deactivate 命令停用你的虛擬環境。
(venv)$ deactivate
virtualenvwrapper
virtualenvwrapper 是一個用於管理 virtualenv 建立的虛擬環境的軟體包。我不想提到這個工具,直到你看到了 virtualenv 的基礎知識以便你理解它改善了什麼以及為什麼我們應該使用它。
上一部分建立的虛擬環境目錄會給你的項目庫帶來一些混亂。你只需要啟用虛擬環境和它進行互動,但是它不應該出現在版本控制中,因此這個虛擬環境目錄就不應該在這裡。解決方案就是使用 virtualenvwrapper。這個軟體包會把所有你的虛擬環境放在一個目錄的方式,通常預設是在 ~/.virtualenvs/。
要安裝 virtualenvwrapper,請按照文檔中的說明,文檔位於 http://virtualenvwrapper.readthedocs.org/en/latest/install.html 。
請確保在安裝 virtualenvwrapper 之前你已經停用所有的虛擬環境。你需要把它安裝在全域系統中,而不是虛擬環境中。
現在,不用運行 virtualenv 來建立一個環境,你需要運行 mkvirtualenv:
$ mkvirtualenv rocketNew python executable in rocket/bin/pythonInstalling setuptools...........[...].....done.Installing pip..................[...].....done.(rocket)$
mkvirtualenv 在你虛擬環境目錄中建立一個檔案夾並且為你啟用虛擬環境。就像上面的 virtualenv 一樣,python 以及 pip 指向虛擬環境中而不是全域系統的二進位檔案。要啟用一個特定的環境,使用命令:workon [environment name]。deactivate 仍然會停用虛擬環境。
安裝依賴包
隨著項目的發展,你會發現依賴包的列表會增大。需要幾十個 Python 包來運行一個 Flask 應用程式的情況並不少見。管理這些最簡單的方法是用一個簡單的文字檔。Pip 能夠產生一個列出所有已安裝的包的文字檔。在一個新的系統上,或者在一個新的剛建立的環境上也能讀取檔案中的列表並且安裝它們中每一個。
pip freeze:
requirements.txt 是一個文字檔,它被許多 Flask 應用程式用來列出運行應用所有需要的包。這個代碼塊用來說明如何建立這個檔案接著下一個代碼塊用來說明在一個新環境中如果使用這個檔案來安裝依賴包。
(rocket)$ pip freeze > requirements.txt$ workon fresh-env(fresh-env)$ pip install -r requirements.txt[...]Successfully installed flask Werkzeug Jinja2 itsdangerous markupsafeCleaning up...(fresh-env)$
人工管理依賴包
隨著項目的發展,你可能會發現 pip freeze 列出的某些包實際上並不是運行應用必須的。你安裝這些包僅僅為開發用的。pip freeze 並不能區分,它僅僅列出目前已經安裝的包。因此,你可能要手動地管理這些依賴包。你可以分別把那些運行應用必須的包放入 require\_run.txt 以及那些開發應用程式需要的包放入 require\_dev.txt 。
版本控制
選擇一個版本控制系統並且使用它。我推薦 Git。從我所看到的,Git 是這些天來新項目最流行的選擇。能夠刪除代碼而不必擔心犯了一個無法復原轉的錯誤是非常寶貴的。你也可以讓你的項目擺脫大量注釋掉的代碼的困擾,因為你可以刪除它們,以後如有需要可以恢複它們。另外,你可以在 GitHub,Bitbucket 或者你自己的 Gitolite 伺服器上備份整個項目。
置身版本控制之外的檔案
我通常會讓一個檔案置身版本控制之外有兩個原因:要麼就是它會讓整個項目顯得混亂,要麼它就是一個很隱私的密鑰/認證。編譯的 .pyc 檔案和虛擬環境 — 如果由於某些原因你沒有使用 virtualenvwrapper — 就是讓項目顯得很混亂的例子。它們不需要在版本控制之中因為它們能夠分別地從 .py 檔案和你的 requirements.txt 檔案重新建立。
API 秘鑰,應用程式秘鑰以及資料庫認證是很隱私的密鑰/認證的樣本。它們不應該出現在版本控制中因為它們的曝光將是一個巨大的安全性漏洞。
當做跟安全有關的決定的時候,我總是喜歡假設我的版本庫將在某個時候變成公開的。這就意味著要保守秘密並且從不假設一個安全性漏洞不會被發現,“誰來猜猜他們能做到”這類型的假設被稱為通過隱匿來實現安全,這是十分槽糕的策略。
當使用 Git 的時候,你可以在你的版本庫中建立名為 .gitignore 的一個特殊檔案。在這個檔案裡,使用列表萬用字元來匹配檔案名稱。任何匹配其中一個模式的檔案名稱都會被 Git 給忽略掉。我推薦使用 .gitignore 來控制不需要版本控制的檔案。例如:
*.pycinstance/
Instance 檔案夾是用於以一種更安全地方式提供給你的應用程式敏感組態變數。我將會在後面更多地談到它。
你可以閱讀更多的關於 .gitignore 的內容從這裡: http://git-scm.com/docs/gitignore
調試
1.偵錯模式
Flask 有一個稱為偵錯模式方便的功能。要開啟調試功能的話,你只必須在你的開發配置中設定 debug = True。當它開啟的時候,伺服器會在代碼變化的時候自動載入並且出錯的時候會伴隨著一個堆疊追蹤和一個互動式控制台。
小心!不要在生產環境中使用偵錯模式。互動式控制台允許執行任意代碼並會是一個巨大的安全性漏洞。
2.Flask-DebugToolbar
Flask-DebugToolbar 是另一個非常了不起的工具,它可以協助在你的應用程式中調試問題。在偵錯模式下,它會把一個側邊欄置於你的應用程式的每一頁上。側邊欄提供了有關 SQL 查詢,日誌記錄,版本,模板,配置和其它有趣的資訊,使得更容易地跟蹤問題。
看看快速入門中的 偵錯模式。在 Flask 官方文檔 中有一些關於錯誤處理,日誌記錄以及使用調試器等不錯的資訊。
Flask 工程配置
當你學習 Flask 的時候,配置看起來很簡單。你只要在 config.py 中定義一些變數接著一切就能工作了。當你開始必須要管理生產應用的配置的時候,這些簡單性開始消失了。你可能需要保護 API 金鑰以及為不同的環境使用不同的配置(例如,開發和生產環境)。在本章節中我們會介紹 Flask 一些先進的功能,它可以使得管理配置容易些。
簡單的例子
一個簡單的應用程式可能不會需要任何這些複雜的功能。你可能只需要把 config.py 放在你的倉庫/版本庫的根目錄並且在 app.py 或者 yourapp/\\_init\\_.py 中載入它。
config.py 檔案中應該每行包含一個組態變數賦值。當你的應用程式初始化的時候,在 config.py 中的組態變數用於配置 Flask 和它的擴充並且它們能夠通過 app.config 字典訪問到 – 例如,app.config["DEBUG"]。
DEBUG = True # Turns on debugging features in FlaskBCRYPT_LEVEL = 12 # Configuration for the Flask-Bcrypt extensionMAIL_FROM_EMAIL = "robert@example.com" # For use in application emails
配置的變數可以被 Flask,它的擴充或者你來使用。這個例子中, 每當我們在一封事務性郵件中需要預設的 “寄件者” 的時候,我們可以使用 app.config["MAIL_FROM_EMAIL"] – 例如,密碼重設。把這些資訊放置於一個組態變數中使得以後能夠容易地修改它。
# app.py or app/__init__.pyfrom flask import Flaskapp = Flask(__name__)app.config.from_object('config')# Now we can access the configuration variables via app.config["VAR_NAME"].
- DEBUG: 為你提供了調試錯誤的一些方便的工具。 這包括一個基於 Web 的堆疊追蹤和互動 Python 控制台。在開發環境中設定成 True; 生產環境中設定成 False。
- SECRET\_KEY:這是 Flask 用來為 cookies 簽名的密鑰。 它也能被像 Flask-Bcrypt 類的擴充使用。 你應該在你的執行個體檔案夾中定義它, 這樣可以遠離版本控制。 你可以在下一個章節中閱讀更多關於樣本檔案夾的內容。一般情況下這應該是一個複雜的隨機值。
- BCRYPT\_LEVEL:如果你使用 Flask-Bcrypt 來散列使用者密碼的話, 你需要指定一個“迴圈”數,這個數是在執行散列密碼的 演算法需要的。如果你不使用 Flask-Bcrypt,你可以 忽略這裡。用於散列密碼的迴圈數越大,攻擊者猜測密碼 的時間會越長。同時,迴圈數越大會增加散列密碼的時間。後面我們會給出在 Flask 應用中 使用 Bcrypt 的一些最佳實務。
確保在生產環境中 DEBUG 設定成 False。如果保留 DEBUG 為 True,它允許使用者在你的伺服器上執行任意的 Python。
執行個體檔案夾
有時候你需要定義包含敏感資訊的組態變數。我們想要從 config.py 中分離這些變數並且讓它們保留在倉庫/版本庫之外。你可能會隱藏像資料庫密碼以及 API 金鑰的一些敏感資訊,或者定義於特定於指定機器的組態變數。為讓實現這些要求更加容易些,Flask 提供了一個叫做 instance folders 的功能。執行個體檔案夾是倉庫/版本庫下的一個子目錄並且包含專門為這個應用程式的執行個體的一個設定檔。我們不希望它提交到版本控制。
config.pyrequirements.txtrun.pyinstance/ config.pyyourapp/ __init__.py models.py views.py templates/ static/
使用執行個體檔案夾
我們使用 app.config.from_pyfile() 來從一個執行個體檔案夾中載入組態變數。當我們調用 Flask() 來建立我們的應用的時候,如果我們設定了 instance_relative_config=True, app.config.from_pyfile() 將會從 instance/ 目錄載入指定檔案。
# app.py or app/__init__.pyapp = Flask(__name__, instance_relative_config=True)app.config.from_object('config')app.config.from_pyfile('config.py')
現在我們可以像在 config.py 中那樣在 instance/config.py 中定義組態變數。你也應該把你的執行個體檔案夾加入到版本控制系統的忽略列表中。要使用 Git 做到這一點的話,你需要在 .gitignore 新的一行中添加 instance/ 。
密鑰
執行個體檔案夾的隱私性成為在其裡面定義不想暴露到版本控制的密鑰的最佳候選。這些密鑰可能包含了你的應用的密鑰或者第三方 API 金鑰。如果你的應用是開源的或者以後可能會公開的話,這一點特別重要。我們通常要求其他使用者或者貢獻者使用自己的密鑰。
# instance/config.pySECRET_KEY = 'Sm9obiBTY2hyb20ga2lja3MgYXNz'STRIPE_API_KEY = 'SmFjb2IgS2FwbGFuLU1vc3MgaXMgYSBoZXJv'SQLALCHEMY_DATABASE_URI= \\"postgresql://user:TWljaGHFgiBCYXJ0b3N6a2lld2ljeiEh@localhost/databasename"
基於環境的配置
如果在你的生產環境和開發環境中的差異非常小的話,你可能想要使用執行個體檔案夾來處理配置的變化。定義在 'instance/config.py' 檔案中的組態變數能夠覆蓋 'config.py' 中的值。你只需要在 'app.config.from_object()' 後調用 'app.config.from_pyfile()'。這樣用法的好處之一就是在不同的機器上修改你的應用的配置。
# config.pyDEBUG = FalseSQLALCHEMY_ECHO = False# instance/config.pyDEBUG = TrueSQLALCHEMY_ECHO = True
在生產環境上,我們略去上面 'instance/-config.py' 中的組態變數,它會退回到定義在 'config.py' 中的值。
瞭解更多關於 Flask-SQLAlchemy 的 配置項。(中文版的位於:http://www.pythondoc.com/flask-sqlalchemy/config.html#configuration-keys)
基於環境變數配置
執行個體檔案夾不應該出現在版本控制中。這就意味著你將無法跟蹤你的執行個體配置的變化。如果只是一、兩個變數這可能不是什麼問題,但是如果你在不同的環境上(生產,預升級,開發,等等)配置都有些微調話,你就不會想要存在丟失它們的風險。
Flask 給我們選擇設定檔的能力,它可以基於一個環境變數的值來載入不同的設定檔。這就意味著在我們的倉庫/版本庫裡,我們可以有多個設定檔並且總會載入正確的那一個。一旦我們有多個設定檔的話,我可以把它們移入它們自己 config 檔案夾中。
requirements.txtrun.pyconfig/ __init__.py # Empty, just here to tell Python that it's a package. default.py production.py development.py staging.pyinstance/ config.pyyourapp/ __init__.py models.py views.py static/ templates/
在上面的檔案清單中我們有多個不同的設定檔。
- config/default.py: 預設的配置值,可用於所有的環境或者被個人的環境給覆蓋。
- config/development.py: 用於開發環境的配置值。這裡你可能會指定本機資料庫的 URI。
- config/production.py: 用於生產環境的配置值。在這裡 DEBUG 一定要設定成 False。
- config/staging.py: 根據開發進度,你可能會有一個類比生產環境,這個檔案主要用於這種情境。
為了決定要載入哪個設定檔,我們會調用 'app.config.from_envvar()'。
# yourapp/\\_\\_init\\_\\_.pyapp = Flask(__name__, instance_relative_config=True)# Load the default configurationapp.config.from_object('config.default')# Load the configuration from the instance folderapp.config.from_pyfile('config.py')# Load the file specified by the APP\\_CONFIG\\_FILE environment variable# Variables defined here will override those in the default configurationapp.config.from_envvar('APP_CONFIG_FILE')
環境變數的值應該是設定檔的絕對路徑。
我們如何設定這個環境變數取決於我們運行應用所在的平台。如果我們運行在一個普通的 Linux 伺服器上,我們可以編寫一個設定環境變數的 shell 指令碼並且運行 run.py。
# start.shAPP\\_CONFIG\\_FILE=/var/www/yourapp/config/production.pypython run.py
start.sh 對於每一個環境都是獨一無二的,因此它應該被排除在版本控制之外。在 Heroku 上,我們需要使用 Heroku 工具來設定環境變數。這種設定方式也適用於其它的 PaaS 平台。