zoukankan      html  css  js  c++  java
  • 用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog

    目录

    前文列表

    用 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)_应用蓝图来重构项目

    工厂模式

    工厂模式:就是通过某一个接口函数或对象来创建另一个对象,而这个接口函数也称之为工厂函数。 工厂模式使一个类的实例化延迟到其子类。也就是说工厂模式可以推迟到在程序运行的时候才动态决定要创建哪个类的实例,而不是在编译时就必须知道要实例化哪个类

    工厂函数:一个用于创建对象的接口(create_object_interface(variables)),让子类来决定(根据不同 variables 作为条件来判断)实例化那一个类的对象。

    EXAMPLE:

    #!/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 环境(env)的上下文来动态的改变 app 的初始配置 config,达到了服务器会根据不同的 env 来得到正确 app config 的效果。
    • 这样会让测试变得简单,因为我们随时可以快速的转换 app config 并开展测试。
    • 反之,也能够使用相同的 config 来生成多个相同的 app object,这对在跨多个服务器进行流量负载均衡的时候是很有用的。

    • jmilkfansblog/__init__.py

    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 对象。

    • manage.py

    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 对象,能够在程序运行的时候才被决定,这种自动适应不同运行环境的能力,使得程序更加灵活、健壮。

    相关阅读:

  • 相关阅读:
    01矩阵扩展
    蒙特卡罗仿真
    某幂相关数学结论
    分式乘法变加减
    ICPC模板排版工具
    windows下mysql使用实录
    随机题目小结
    工作用linux命令汇总
    小数化分数的O(log2n)解法
    博弈总结
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13310700.html
Copyright © 2011-2022 走看看