<style>
html, body, .ui-content {
background-color: #333;
color: #ddd;
}
body > .ui-infobar {
display: none;
}
.ui-view-area > .ui-infobar {
display: block;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
color: #ddd;
}
.markdown-body h1,
.markdown-body h2 {
border-bottom-color: #ffffff69;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #fff;
}
.markdown-body img {
background-color: transparent;
}
.ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a {
color: white;
border-left: 2px solid white;
}
.expand-toggle:hover,
.expand-toggle:focus,
.back-to-top:hover,
.back-to-top:focus,
.go-to-bottom:hover,
.go-to-bottom:focus {
color: white;
}
.ui-toc-dropdown {
background-color: #333;
}
.ui-toc-label.btn {
background-color: #191919;
color: white;
}
.ui-toc-dropdown .nav>li>a:focus,
.ui-toc-dropdown .nav>li>a:hover {
color: white;
border-left: 1px solid white;
}
.markdown-body blockquote {
color: #bcbcbc;
}
.markdown-body table tr {
background-color: #5f5f5f;
}
.markdown-body table tr:nth-child(2n) {
background-color: #4f4f4f;
}
.markdown-body code,
.markdown-body tt {
color: #eee;
background-color: rgba(230, 230, 230, 0.36);
}
a,
.open-files-container li.selected a {
color: #5EB7E0;
}
</style>}
# Python + Flask 虛擬美國股票交易網站 Part1 (配置+工廠函數)
###### tags: `CS50` `Python` `Flask`
### 前言
四月開始上哈佛的CS50後,最後一個Project是要用Python + Flask 製作一個虛擬股票交易網站,做了蠻久一段時間的,還去買了[李辉 - Flask Web开发实战 helloflask](http://helloflask.com/book/1/) 來讀,最後總算做出來一個雛形,雖然有點陽春,不過該有的基本功能都有。
用[XMind](http://helloflask.com/book/1/) 畫了一下架構圖

#
### 使用套件
Flask
Bootstrap-Flask
Sqlalchemy
DebugToolbarExtension
LoginManager
Moment
CSRFProtect
## 配置 vfinance/setting.py
```
import os
prefix = 'sqlite:////'
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
class BaseConfig(object):
SECRET_KEY = os.getenv("SECRET_KEY", "dev key")
DEBUG_TB_INTERCEPT_REDIRECTS = False
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_RECORD_QUERIES = True
# Flag used to enable CSRF protection for image uploading
CKEDITOR_ENABLE_CSRF = True
# The URL or endpoint that handles file browser.
CKEDITOR_FILE_UPLOADER = 'admin.upload_image'
TEMPLATES_AUTO_RELOAD = True
class DevelopmentConfig(BaseConfig):
SQLALCHEMY_DATABASE_URI = prefix + os.path.join(basedir, 'vfinance.db')
config = {
"development" :DevelopmentConfig
}
```
`DEBUG_TB_INTERCEPT_REDIRECTS = False` :
FlaskDebugToolbar會攔截重新導向的請求,將DEBUG_TB_INTERCEPT_REDIRECTS配置設定為False可以關閉這個特性。
`DEBUG_TB_INTERCEPT_REDIRECTS = False` :
安裝並初始化FlaskSQLAlchemy後,啓動程序時會看到命令行下有一行警告信息。這是因為FlaskSQLAlchemy建議你設置SQLALCHEMY_TRACK_MODIFICATIONS配置變量,這個配置變量決定是否追蹤對象的修改,這用於FlaskSQLAlchemy的事件通知系統。這個配置鍵的默認值為None,如果沒有特殊需要,我們可以把它設為False來關閉
`SQLALCHEMY_RECORD_QUERIES = True`
Can be used to explicitly disable or enable query recording. Query recording automatically happens in debug or testing mode. 自動記錄query的紀錄
#
在Setting.py文件的最後,建立了一個用來儲存配置名稱及對應配置的dictionary,之後便可以在建立程式實例後使用app.config.from_object()方法來加載配置。
## 在工廠函數載入設置、註冊藍本 vfinance/__init__.py
```
def create_app(config_name = None):
if config_name == None:
config_name = os.getenv("FLASK_CONFIG", "development")
app = Flask('vfinance')
app.config.from_object(config[config_name])
app.register_blueprint(home_bp)
app.register_blueprint(admin_bp, url_prefix = "/admin")
app.register_blueprint(auth_bp, url_prefix = "/auth")
return app
```
## 擴充外掛 vfinance/extensions.py
```
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_debugtoolbar import DebugToolbarExtension
from flask_moment import Moment
from flask_wtf import CSRFProtect
bootstrap = Bootstrap()
db = SQLAlchemy()
login_manager = LoginManager()
toolbar = DebugToolbarExtension()
moment = Moment()
csrf = CSRFProtect()
```
之後便可在工廠函數中導入以上的擴充對象,並使用init_app()函數傳入程式實例完成初始化
## vfinance/__init__.py
```
from vfinance.extensions import bootstrap, db, login_manager, toolbar, moment, csrf
def create_app(config_name = None):
...
app = Flask('vfinance')
...
bootstrap.init_app(app)
db.init_app(app)
login_manager.init_app(app)
toolbar.init_app(app)
moment.init_app(app)
csrf.init_app(app)
return app
```
除了外掛擴充外,還有很多函數要註冊到程序上,例如錯誤處理函數、上下文處理函數等。為了避免太複雜,可以根據類別把這些程式碼分類成多個函數,如下:
## vfinance/__init__.py:組織工廠函數
```
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
config_name = os.getenv("FLASK_CONFIG", "develpement")
if not os.environ.get("API_KEY"):
raise RuntimeError("API_KEY not set")
def create_app(config_name = None):
if config_name == None:
config_name = os.getenv("FLASK_CONFIG", "development")
app = Flask('vfinance')
app.config.from_object(config[config_name])
app.jinja_env.filters["usd"] = usd
app.jinja_env.globals["lookup"] = lookup
app.jinja_env.auto_reload = True
register_blueprints(app) # 註冊藍本
register_commands(app) # 註冊自定義shell命令
register_extensions(app) # 註冊擴充功能
register_template_context(app) # 註冊模板上下文處理函數
return app
def register_blueprints(app):
app.register_blueprint(home_bp)
app.register_blueprint(admin_bp, url_prefix = "/admin")
app.register_blueprint(auth_bp, url_prefix = "/auth")
def register_extensions(app):
bootstrap.init_app(app)
db.init_app(app)
login_manager.init_app(app)
toolbar.init_app(app)
moment.init_app(app)
csrf.init_app(app)
def register_shell_context(app):
@app.shell_context_processor
def make_shell_context():
pass
def register_template_context(app):
pass
def register_commands(app):
...
```
接著執行flask run來啟動程序
```
$flask run
```