用 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 对象,能够在程序运行的时候才被决定,这种自动适应不同运行环境的能力,使得程序更加灵活、健壮。
用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象的更多相关文章
- 用 Flask 来写个轻博客
用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...
- 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...
- 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五
目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...
- 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...
- 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三
目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...
- 用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 构建 RESTful Flask API 定义资源路由 格式 ...
- 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一
目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...
- 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...
- 用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能
Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 实现文章管理功能 实现效果 前文列表 用 Flask 来写个 ...
随机推荐
- C#=> 栈模仿堆的操作
//原理,利用两个栈,互相作用,来模仿堆的效果,先进先出.. using System; using System.Collections.Generic; using System.Linq; us ...
- java_第一年_JDBC(2)
上篇说到,通过JDBC可实现java编程程序和mysql数据库进行连接并交互,而交互后所形成的结果集是通过ResultSet对象来操作的. 创建ResultSet对象: stmt = conn.cre ...
- mysql-时间格式
SELECT DATE_FORMAT('2019-1-1 15:1:1.099','%Y-%m-%d %H:%i:%s.%f') -- 2019-01-01 15:01:01.099000 %a 缩 ...
- sublime text3 安装插件
遇到的问题1: 软件中无此属性 打开Packages目录,Preferences > Browse Packages 就可以进入这个目录.$ cd Packages/$ git clone ht ...
- linux性能分析工具free
- Sass函数:Sass Maps的函数-map-get($map,$key)
map-get($map,$key) 函数的作用是根据 $key 参数,返回 $key 在 $map 中对应的 value 值.如果 $key 不存在 $map中,将返回 null 值.此函数包括两个 ...
- python+django+pycharm 环境配置 (window7)
一.python环境配置 登录python官网,下载windows版的python,本项目使用32位的python2.7.6,下载地址: http://www.python.org/ftp/pytho ...
- 太可怕了!黑客是如何攻击劫持安卓用户的DNS?
最近发现的针对Android设备的广泛路由器的DNS劫持恶意软件现在已升级为针对iOS设备以及桌面用户的功能. 被称为RoamingMantis的恶意软件最初发现在上个月劫持了互联网路由器,以散布旨在 ...
- centos6.5 相关命令
挂载U盘 1.进入mnt目录: #cd /mnt 2.新建一个USB目录: #mkdir usb 3.查看U盘的目录: #fdisk –l 4.挂载: #mount –t vfat /dev/sdb1 ...
- RabbitMQ:伪延时队列
目录 一.什么是延时队列 二.RabbitMQ实现 三. 延时队列的问题 四.解决RabbitMQ的伪延时方案 ps:伪延时队列先卖个关子,我们先了解下延时队列. 一.什么是延时队列 所谓延时队列是指 ...