<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/) 畫了一下架構圖 ![](https://i.imgur.com/YbvNzOz.png) # ### 使用套件 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 ```