用 Flask 來寫個輕博客 (18) — 使用工廠模式來生成應用對象

目錄

前文列表

用 Flask 來寫個輕博客 (1) — 建立項目
用 Flask 來寫個輕博客 (2) — Hello World!
用 Flask 來寫個輕博客 (3) — (M)VC_鏈接 MySQL 和 SQLAlchemy
用 Flask 來寫個輕博客 (4) — (M)VC_建立數據模型和表
用 Flask 來寫個輕博客 (5) — (M)VC_SQLAlchemy 的 CRUD 詳解
用 Flask 來寫個輕博客 (6) — (M)VC_models 的關係(one to many)
用 Flask 來寫個輕博客 (7) — (M)VC_models 的關係(many to many)
用 Flask 來寫個輕博客 (8) — (M)VC_Alembic 管理數據庫結構的升級和降級
用 Flask 來寫個輕博客 (9) — M(V)C_Jinja 語法基礎快速概覽
用 Flask 來寫個輕博客 (10) — M(V)C_Jinja 經常使用過濾器與 Flask 特殊變量及方法
用 Flask 來寫個輕博客 (11) — M(V)C_建立視圖函數
用 Flask 來寫個輕博客 (12) — M(V)C_編寫和繼承 Jinja 模板
用 Flask 來寫個輕博客 (13) — M(V)C_WTForms 服務端表單檢驗
用 Flask 來寫個輕博客 (14) — M(V)C_實現項目首頁的模板
用 Flask 來寫個輕博客 (15) — M(V)C_實現博文頁面評論表單
用 Flask 來寫個輕博客 (16) — MV(C)_Flask Blueprint 藍圖
用 Flask 來寫個輕博客 (17) — MV(C)_應用藍圖來重構項目 css

工廠模式

工廠模式:就是經過某一個接口函數或對象來建立另外一個對象,而這個接口函數也稱之爲工廠函數。 工廠模式使一個類的實例化延遲到其子類。也就是說工廠模式能夠推遲到在程序運行的時候才動態決定要建立哪一個類的實例,而不是在編譯時就必須知道要實例化哪一個類python

工廠函數:一個用於建立對象的接口(create_object_interface(variables)),讓子類來決定(根據不一樣 variables 做爲條件來判斷)實例化那一個類的對象。mysql

EXAMPLE:sql

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class Circle(object):
    def draw(self):
        print 'draw circle'

class Rectangle(object):
    def draw(self):
        print 'draw Rectangle'

class ShapeFactory(object):
    def create(self, shape):
        if shape == 'Circle':
            return Circle()
        elif shape == 'Rectangle':
            return Rectangle()
        else:
            return None

fac = ShapeFactory()
obj = fac.create('Circle')
obj.draw()

使用工廠方法 Factory Method 建立 app 對象

這樣作的好處shell

  • 能夠利用 shell 環境(env)的上下文來動態的改變 app 的初始配置 config,達到了服務器會根據不一樣的 env 來獲得正確 app config 的效果。
  • 這樣會讓測試變得簡單,由於咱們隨時能夠快速的轉換 app config 並開展測試。
  • 反之,也可以使用相同的 config 來生成多個相同的 app object,這對在跨多個服務器進行流量負載均衡的時候是頗有用的。數據庫

  • jmilkfansblog/__init__.pyjson

from flask import Flask, redirect, url_for

from models import db
from controllers import blog

def create_app(object_name):
    """Create the app instance via `Factory Method`"""

    app = Flask(__name__)
    # Set the app config 
    app.config.from_object(object_name)

    # Will be load the SQLALCHEMY_DATABASE_URL from config.py to db object
    db.init_app(app)

    @app.route('/')
    def index():
        # Redirect the Request_url '/' to '/blog/'
        return redirect(url_for('blog.home'))

    # Register the Blueprint into app object
    app.register_blueprint(blog.blog_blueprint)

    return app
  • NOTE 1:將 app.config.from_object(object_name) 接收的參數定義成一個變量,這樣就能夠經過接收不一樣類型的實參來生成不一樣的 app 對象。
  • NOTE 2:在 create_app() 這個函數中,完成了 db/config/route/blueprint 的初始化工做以後,再返回這個 app 對象。flask

  • manage.pyapi

import os

from flask.ext.script import Manager, Server
from flask.ext.migrate import Migrate, MigrateCommand

from jmilkfansblog import create_app
from jmilkfansblog import models


# Get the ENV from os_environ
env = os.environ.get('BLOG_ENV', 'dev')
# Create thr app instance via Factory Method
app = create_app('jmilkfansblog.config.%sConfig' % env.capitalize())
# Init manager object via app object
manager = Manager(app)

# Init migrate object via app and db object
migrate = Migrate(app, models.db)

# Create some new commands
manager.add_command("server", Server(host='192.168.1.222', port=8089))
manager.add_command("db", MigrateCommand)


@manager.shell
def make_shell_context():
    """Create a python CLI. return: Default import object type: `Dict` """
    return dict(app=app,
                db=models.db,
                User=models.User,
                Post=models.Post,
                Comment=models.Comment,
                Tag=models.Tag,
                Server=Server)

if __name__ == '__main__':
    manager.run()
  • NOTE 1:如今的 manager shell 在每次啓動的時候,都會獲取一次 OS 的環境變量,並以此來建立 app 對象。
  • NOTE 2:默認使用 DevConfig 配置
  • NOTE 3:這樣咱們就能夠根據手動設置的環境變量來達到生成相應的環境變量的效果,而不須要修改任何源碼。

EXAMPLE 1:使用默認配置服務器

(env) [root@flask-dev JmilkFan-s-Blog]# python manage.py shell

>>> app
<Flask 'jmilkfansblog'>
>>> app.config
<Config {'JSON_AS_ASCII': True, 'USE_X_SENDFILE': False, 'SQLALCHEMY_DATABASE_URI': 'mysql+pymysql://root:fanguiju@127.0.0.1:3306/myblog?charset=utf8', 'SQLALCHEMY_TRACK_MODIFICATIONS': None, 'SQLALCHEMY_POOL_SIZE': None, 'SQLALCHEMY_POOL_TIMEOUT': None, 'SESSION_COOKIE_PATH': None, 'SQLALCHEMY_RECORD_QUERIES': None, 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_NAME': 'session', 'SQLALCHEMY_BINDS': None, 'SQLALCHEMY_POOL_RECYCLE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'LOGGER_HANDLER_POLICY': 'always', 'LOGGER_NAME': 'jmilkfansblog', 'DEBUG': True, 'SQLALCHEMY_COMMIT_ON_TEARDOWN': False, 'SECRET_KEY': 'c8e6ff3e4687709ca10a1138a17cd397', 'EXPLAIN_TEMPLATE_LOADING': False, 'SQLALCHEMY_NATIVE_UNICODE': None, 'MAX_CONTENT_LENGTH': None, 'SQLALCHEMY_ECHO': False, 'APPLICATION_ROOT': None, 'SERVER_NAME': None, 'PREFERRED_URL_SCHEME': 'http', 'JSONIFY_PRETTYPRINT_REGULAR': True, 'TESTING': False, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'PROPAGATE_EXCEPTIONS': None, 'TEMPLATES_AUTO_RELOAD': None, 'TRAP_BAD_REQUEST_ERRORS': False, 'JSON_SORT_KEYS': True, 'JSONIFY_MIMETYPE': 'application/json', 'SQLALCHEMY_MAX_OVERFLOW': None, 'SESSION_COOKIE_HTTPONLY': True, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SESSION_COOKIE_SECURE': False, 'TRAP_HTTP_EXCEPTIONS': False}>

EXAMPLE 2:手動設置使用 Config 配置

(env) [root@flask-dev JmilkFan-s-Blog]# export BLOG_ENV=""
(env) [root@flask-dev JmilkFan-s-Blog]# echo $BLOG_ENV

(env) [root@flask-dev JmilkFan-s-Blog]# python manage.py shell
>>> app.config
<Config {'JSON_AS_ASCII': True, 'USE_X_SENDFILE': False, 'SQLALCHEMY_DATABASE_URI': 'sqlite://', 'SQLALCHEMY_TRACK_MODIFICATIONS': None, 'SQLALCHEMY_POOL_SIZE': None, 'SQLALCHEMY_POOL_TIMEOUT': None, 'SESSION_COOKIE_PATH': None, 'SQLALCHEMY_RECORD_QUERIES': None, 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_NAME': 'session', 'SQLALCHEMY_BINDS': None, 'SQLALCHEMY_POOL_RECYCLE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'LOGGER_HANDLER_POLICY': 'always', 'LOGGER_NAME': 'jmilkfansblog', 'DEBUG': False, 'SQLALCHEMY_COMMIT_ON_TEARDOWN': False, 'SECRET_KEY': 'c8e6ff3e4687709ca10a1138a17cd397', 'EXPLAIN_TEMPLATE_LOADING': False, 'SQLALCHEMY_NATIVE_UNICODE': None, 'MAX_CONTENT_LENGTH': None, 'SQLALCHEMY_ECHO': False, 'APPLICATION_ROOT': None, 'SERVER_NAME': None, 'PREFERRED_URL_SCHEME': 'http', 'JSONIFY_PRETTYPRINT_REGULAR': True, 'TESTING': False, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'PROPAGATE_EXCEPTIONS': None, 'TEMPLATES_AUTO_RELOAD': None, 'TRAP_BAD_REQUEST_ERRORS': False, 'JSON_SORT_KEYS': True, 'JSONIFY_MIMETYPE': 'application/json', 'SQLALCHEMY_MAX_OVERFLOW': None, 'SESSION_COOKIE_HTTPONLY': True, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SESSION_COOKIE_SECURE': False, 'TRAP_HTTP_EXCEPTIONS': False}>

使用工廠函數生成的 app 對象,可以在程序運行的時候才被決定,這種自動適應不一樣運行環境的能力,使得程序更加靈活、健壯。

相關文章
相關標籤/搜索