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


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM