1. 程式人生 > >Flask實戰-留言板-安裝虛擬環境、使用包組織代碼

Flask實戰-留言板-安裝虛擬環境、使用包組織代碼

dot date 處理 nbsp 完成後 and 定義 clas odi

Flask實戰

留言板

創建項目目錄messageboard,從GreyLi的代碼中把Pipfile和Pipfile.lock文件拷貝過來,這兩個文件中定義了虛擬環境中需要安裝的包的信息和位置,進入messageboard目錄使用pipenv創建虛擬環境,這會同時安裝所有依賴(--dev選項用來包括開發依賴), 安裝完成後激活虛擬環境。

安裝虛擬環境

pipenv install –dev

技術分享圖片

激活:

flask shell

技術分享圖片

查看虛擬環境中安裝的包:

技術分享圖片

Pipfile:用來下載依賴包的
[[source]]
url = "https://pypi.python.org/simple
" verify_ssl = true name = "pypi" [dev-packages] watchdog = "*" faker = "*" [packages] bootstrap-flask = "*" flask-moment = "*" flask-sqlalchemy = "*" python-dotenv = "*" flask-wtf = "*" flask = "*"

Pipfile.lock: 用來下載依賴包的
{
    "_meta": {
        "hash": {
            
"sha256": "90ecde6aebc889b8de105fb6b1394a6900ce33cf1be970cba63c0f6d56b158df" }, "pipfile-spec": 6, "requires": {}, "sources": [ { "name": "pypi", "url": "https://pypi.python.org/simple", "verify_ssl": true } ] },
"default": { "bootstrap-flask": { "hashes": [ "sha256:1f7462261b8104687807ce74b397270e7ade07c491ad7d53f215940d8433d756", "sha256:ce5cf19c46b8d385923dc2f9ca76b92fc08c1a8d7dcb5d177325a85a94d71045" ], "index": "pypi", "version": "==1.0.9" }, "click": { "hashes": [ "sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d", "sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b" ], "version": "==6.7" }, "flask": { "hashes": [ "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" ], "index": "pypi", "version": "==1.0.2" }, "flask-moment": { "hashes": [ "sha256:71a601fcd5be4742227251641cb706c109680b54c5fb25c5d2ed96e576ec3b4d", "sha256:af7ccd599d85e751ff1f7661904daa51df9950e9bc9bd4ccf174bd38ccbc401f" ], "index": "pypi", "version": "==0.6.0" }, "flask-sqlalchemy": { "hashes": [ "sha256:3bc0fac969dd8c0ace01b32060f0c729565293302f0c4269beed154b46bec50b", "sha256:5971b9852b5888655f11db634e87725a9031e170f37c0ce7851cf83497f56e53" ], "index": "pypi", "version": "==2.3.2" }, "flask-wtf": { "hashes": [ "sha256:5d14d55cfd35f613d99ee7cba0fc3fbbe63ba02f544d349158c14ca15561cc36", "sha256:d9a9e366b32dcbb98ef17228e76be15702cd2600675668bca23f63a7947fd5ac" ], "index": "pypi", "version": "==0.14.2" }, "itsdangerous": { "hashes": [ "sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519" ], "version": "==0.24" }, "jinja2": { "hashes": [ "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" ], "version": "==2.10" }, "markupsafe": { "hashes": [ "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665" ], "version": "==1.0" }, "python-dotenv": { "hashes": [ "sha256:4f3582904d08dac5ab4c9aa44cb17ce056c9a35e585cfda6183d80054d247307", "sha256:cb8cd327109898c7725f76c5256a081e8a9efe72ebbf127f8d1221ceb7f38bf2" ], "index": "pypi", "version": "==0.10.0" }, "sqlalchemy": { "hashes": [ "sha256:72325e67fb85f6e9ad304c603d83626d1df684fdf0c7ab1f0352e71feeab69d8" ], "version": "==1.2.10" }, "werkzeug": { "hashes": [ "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" ], "version": "==0.14.1" }, "wtforms": { "hashes": [ "sha256:0cdbac3e7f6878086c334aa25dc5a33869a3954e9d1e015130d65a69309b3b61", "sha256:e3ee092c827582c50877cdbd49e9ce6d2c5c1f6561f849b3b068c1b8029626f1" ], "version": "==2.2.1" } }, "develop": { "argh": { "hashes": [ "sha256:a9b3aaa1904eeb78e32394cd46c6f37ac0fb4af6dc488daa58971bdc7d7fcaf3", "sha256:e9535b8c84dc9571a48999094fda7f33e63c3f1b74f3e5f3ac0105a58405bb65" ], "version": "==0.26.2" }, "faker": { "hashes": [ "sha256:0e9a1227a3a0f3297a485715e72ee6eb77081b17b629367042b586e38c03c867", "sha256:b4840807a94a3bad0217d6ed3f9b65a1cc6e1db1c99e1184673056ae2c0a4c4d" ], "index": "pypi", "version": "==0.8.17" }, "ipaddress": { "hashes": [ "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" ], "markers": "python_version == ‘2.7‘", "version": "==1.0.22" }, "pathtools": { "hashes": [ "sha256:7c35c5421a39bb82e58018febd90e3b6e5db34c5443aaaf742b3f33d4655f1c0" ], "version": "==0.1.2" }, "python-dateutil": { "hashes": [ "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8" ], "version": "==2.7.3" }, "pyyaml": { "hashes": [ "sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b", "sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf", "sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a", "sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3", "sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1", "sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1", "sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613", "sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04", "sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f", "sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537", "sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531" ], "version": "==3.13" }, "six": { "hashes": [ "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" ], "version": "==1.11.0" }, "text-unidecode": { "hashes": [ "sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d", "sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc" ], "version": "==1.2" }, "watchdog": { "hashes": [ "sha256:7e65882adb7746039b6f3876ee174952f8eaaa34491ba34333ddf1fe35de4162" ], "index": "pypi", "version": "==0.8.3" } } }

使用包組織代碼

把所有的代碼都放在app.py裏會導致可讀性降低,不方便管理,我們需要更好的代碼組織方式。

Flask對項目的組織方式沒有要求,對於小型項目,你完全可以把代碼都放在一個主模塊裏,隨著項目越來越大,更好的處理方式是將單一的模塊升級為包(package),把不同部分的代碼分模塊存放。

在python中,每一個有效的python文件(.py)都是模塊。每一個包含__init__.py文件的文件夾都被視作包,包讓你可以使用文件夾來組織模塊。__init__.py文件通常被稱作構造文件。文件可以為空,也可以用來放置包的初始化代碼。當包或包內的模塊被導入時,構造文件將被自動執行。

messageboard程序的核心組件都放到一個包中,這個包稱為程序包,包的程序通常使用程序名稱,即messageBoard,有時為了方便管理也會使用app作為包名稱。除了程序代碼,一個基本的Flask項目還包括其他必要的組件,下面列一下程序包主要組件及其功能說明:messageBoard/ --程序包

messageBoard/__init__.py --構造文件,包含程序實例

messageBoard/templates/ --模板

messageBoard/static/ --靜態文件,其中又包含js和css文件夾

messageBoard/views.py --視圖函數

messageBoard/forms.py --表單

messageBoard/errors.py --錯誤處理

messageBoard/models.py -- 數據庫模型

messageBoard/commands.py -- 自定義flask命令

messageBoard/settings.py -- 配置文件

在後面的開發中,各類代碼都會按照類別存儲在對應的模塊中。這裏的模塊並不是固定的,如果需要組織其他代碼,那麽可以自己創建對應的模塊。比如,創建一個callbacks.py腳本來存儲各種註冊在程序實例上的處理函數。相對的,如果不需要創建自定義命令,那麽也可以不創建commands.py腳本。

配置文件

在flask中,配置不僅可以通過config對象直接寫入,還可以從文件中讀取。在messageBoard中,把配置移動到一個單獨的文件中,將其命名為settings.py(也常被命名為config.py)。當在單獨的文件中定義配置時,不再使用config對象添加配置,而是直接以鍵值對的方式先寫出,和保存環境變量的.flaskenv文件非常相似。

messageBoard/settings.py:配置文件
#encoding=utf-8
import os

from messageBoard import app

dev_db = sqlite:/// + os.path.join(os.path.dirname(app.root_path), data.db)  #sqlite絕對路徑格式

SECRET_KEY = os.getenv(SECRET_KEY, secret string)
SQLALCHEMY_TRACK_MODIFICATIONS = False  # 不追蹤對象的修改
SQLALCHEMY_DATABASE_URI = os.getenv(DATABASE_URI, dev__db)

除了從python腳本導入配置,Flask還提供了其他方式,比如使用from_json()方法從JSON文件中導入,或是使用from_object()方法從python對象導入。

上面的配置中,由於配置文件被放到了程序包內,為了定位到位於項目根目錄的數據庫文件,使用os.path.dirname(app.root_path)獲取上層目錄,app.root_path屬性存儲程序實例所在的路徑。數據庫URI和秘鑰都會首先從環境變量獲取。

在創建程序實例後,使用config對象的from_pyfile()方法即可加載配置,傳入配置模塊的文件名作為參數:

messageBoard/messageBoard/__init__.py:

messageBoard/messageBoard/__init__.py:

app = Flask(__name__)
app.config.from_pyfile(settings.py)

創建程序實例

使用包組織程序代碼後,創建程序實例、初始化擴展等操作可以在程序包的構造文件(__init__.py)中實現,如下所示:

messageBoard/__init__.py: 創建程序實例、初始化擴展

#encoding=utf-8

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(messageBoard)
app.config.from_pyfile(settings.py)
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True

db = SQLAlchemy(app)

from messageBoard import views, errors, commands

在單個腳本中創建程序實例時,我們傳入__name__變量作為Flask類構造方法的import_name參數值。因為Flask通過這個值來確認程序路徑,當使用包組織代碼時,為了確保其他擴展或測試框架獲得正確的路徑值,我們最好以硬編碼的形式寫出包名稱作為程序名稱,即messageBoard。

除了直接寫出包名稱,你也可以從__name__變量獲取包名稱,即app=Flask(__name__.split(‘.’)[0])。

當我們啟動程序時,首先被執行的是包含程序實例的腳本,即構造文件。但註冊在程序實例上的各種處理程序均存放在其他腳本中,比如視圖函數存放在view.py中、錯誤處理函數則存放在errors.py中。為了能使用程序實例app註冊的視圖函數,錯誤處理函數,自定義命令函數等和程序實例關聯起來,我們需要在構造文件中導入這些模塊。因為這些模塊也需要從構造文件中導入程序實例,所以為了避免循環依賴,這些導入語句在構造文件的末尾定義。

從構造文件中導入變量時不需要註明構造文件的路徑,只需要從包名稱導入,比如導入在構造文件中定義的程序實例APP,可以使用from messageBoard import app。

Flask在通過FLASK_APP變量定義的魔窟開中尋找程序實例。所以在啟動程序前,我們需要給.flaskenv(需要安裝python-dotenv)中的環境變量FLASK_APP重新賦值,這裏僅寫出包名稱即可:

messageBoard/.flaskenv:

FLASK_APP=messageBoard

Flask實戰-留言板-安裝虛擬環境、使用包組織代碼