Flask:工厂函数和蓝本
我们用pycharm去新建Flask项目的时候,会默认生成开发文件.如下,其中包括static,templates,flask1_prj.py文件

在最初开始的时候,我们的app等声明都是在flask1_prj.py中进行的,然后程序实例的运行也是在一起的.就像下面的这样
app = Flask(__name__)
bootstrap=Bootstrap(app)
app.config['SECRET_KEY']=os.urandom(20)
@app.route('/',methods=['GET','POST'])
def hello_world():
form=NameForm()
if form.validate_on_submit():
session['name']=form.name.data
return redirect(url_for('hello_world'))
print session.get('name')
return render_template('index1.html',form=form,name=session.get('name'))
if __name__ == '__main__':
app.run(host='192.168.0.12',port=8000)
这种组织形式在单个文件中开发程序很放方便.但是有个问题是app是在全局作用域中创建.无法动态修改配置.或者我们想建立多个实例的时候,需要为每个实例配置进行不同的配置.在django中我们每创建一个应用实例的时候,相应的文件结构就已经生成好了,不需要我们做另外的配置,但是在Flask中,这些事情需要我们自己来完成.这就需要用到工厂函数了
前面介绍创建不同配置类的时候,我们就新建了一个config.py文件.然后通过配置选项做不同的配置.那么既然我们要建不同的实例,那么就采用调用一个create_app的函数来生成各个不同的实例,在各自生成的实例中再调用不同的配置.这样的结构我们就成为工厂函数,来看具体的代码实现
首先创建工程结构如下.建立一个app的程序包.里面包含__init__.py,config.py,run.py,model_sqlite.py,manger.py

三个文件的作用分别如下,
__init__.py其中就包含工厂函数,是定义工厂函数的地方
config.py 和之前的配置选项一样,定义各种的配置选项
run.py:主程序.
model_sqlite.py是定义数据模型的地方
manger.py 是配置数据迁移的文件
其中还包含main package. main package包含__init__.py和views.py文件
__init__.py是蓝本的定义文件
views.py是定义视图和路由的地方.
接下来看具体的代码实现:
app package:__init__.py
from flask import Flask,render_template
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
import config
from config import DevelopmentConfig
from .main import main as main_blueprint
bootstrap=Bootstrap()
db=SQLAlchemy()
def create_app(config_name):
app=Flask(__name__)
app.config.from_object(DevelopmentConfig)
config.config[config_name].init_app(app)
bootstrap.init_app(app)
db.init_app(app)
app.register_blueprint(main_blueprint)
return app
create_app函数接收config_name参数,然后在其中进行app的生成.生成后进行各种app的绑定.在这里绑定了bootstrap和db.最终返回app实例
app package:config.py 内容和之前一样,没有区别
import os
basedir=os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY='hello world'
SQLALCHEMY_COMMIT_ON_TEARDOWN=True
ITEMS_PER_PAGE=10
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG=True
SQLALCHEMY_DATABASE_URI='sqlite:///'+os.path.join(basedir,'data.sqlite')
class TestConfig(Config):
TESTING=True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'test.sqlite')
WTF_CSRF_ENABLED = False
config={
'development':DevelopmentConfig,
'testing':TestConfig,
'default':DevelopmentConfig
}
app package:model_sqlite.py 内容也和之前一样
from app import db
class User(db.Model):
__tablename__='Users'
id=db.Column(db.Integer,primary_key=True)
name=db.Column(db.String(64),unique=True,index=True)
age=db.Column(db.Integer)
address=db.Column(db.String(100))
role_id=db.Column(db.Integer,db.ForeignKey("Role.id"))
def __repr__(self):
return '<User %r>' % self.name
class Role(db.Model):
__tablename__='Role'
users=db.relationship('User',backref='Role')
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
address = db.Column(db.String(100))
def __repr__(self):
return '<User %r>' % self.name
app package:manger.py
from app import create_app
from flask_migrate import Migrate,MigrateCommand
from flask_script import Manager
from app import db
from app.model_sqlite import User,Role
app=create_app('development')
manager=Manager(app)
migrate=Migrate(app,db)
manager.add_command('db',MigrateCommand)
if __name__=="__main__":
manager.run()
不知道大家发现一个问题,在之前单文件配置的时候.程序实例存在与全局作用域中,路由可以直接使用app.route装饰器来定义.但现在程序在运行时创建.只有调用create_app()之后才能使用app.route装饰器.这个时候定义路由就比较晚了.
Flask采用蓝本来解决这个问题,蓝本定义的路由处于休眠状态,直到蓝本注册到程序上时,路由才真正成为程序的一部分
有关于蓝本的具体介绍可以参考下面的2个帖子:
https://www.zhihu.com/question/31748237/answer/55313054
http://dormousehole.readthedocs.io/en/latest/blueprints.html
在main package中就是定义蓝本的地方.
__init__.py
from flask import Blueprint
main=Blueprint('main',__name__,template_folder='../template',static_folder='../static') #template_folder和static_folder分别指示模板文件和静态文件的地址
from . import views
views.py:
from app.main import main
@main.route('/')
def index():
return render_template('index.html')
在具体的视图函数中,就采用的是@main.route(‘/’)的方式,而不是@app.route(‘/’)的方式.
当然最后在其中其中 其中在app.__init__.py的create_app需要将蓝本注册到app当中去.app.register_blueprint(main_blueprint).这样路由就和程序实例关联起来了.
最后在run.py中 通过引用create_app的方式就可以运行整个项目了
from app import create_app
app=create_app('development')
if __name__=="__main__":
app.run(host='192.168.0.12', port=8000)
Flask:工厂函数和蓝本的更多相关文章
- flask实战-个人博客-使用工厂函数创建程序实例 --
使用工厂函数创建程序实例 使用蓝本还有一个重要的好处,那就是允许使用工厂函数来创建程序实例.在OOP(Object-Oriented Programming,面向对象编程)中,工厂(factory)是 ...
- (转)论python工厂函数与内建函数
所谓工厂函数就是指这些内建函数都是类对象, 当你调用它们时,实际上是创建了一个类实例. 工厂函数: int(),long(),float(),complex(),bool() str(),unic ...
- jQuery基础的工厂函数以及定时器的经典案例
1. jQuery的基本信息: 1.1 定义: jQuery是JavaScript的程序库之一,它是JavaScript对象和实用函数的封装, 1.2 作用: 许多使用JavaScript能实现的交 ...
- jQuery基础,定时器,工厂函数
这个星期刚刚学的JQuery,下面我来说说我学的这几个例子 jQuery是JavaScript的一个程序库. Jquery的工厂函数$(): 在Jquery中 $符号等价于jquery,作用是将DOM ...
- jQuery1.11源码分析(4)-----Sizzle工厂函数[原创]
在用前两篇讲述完正则表达式.初始化.特性检测之后,终于到了我们的正餐——Sizzle工厂函数! Sizzle工厂函数有四个参数, selector:选择符 context:查找上下文 results: ...
- python--字符工厂函数dict()
字符工厂函数str() class str(object): """ str(object='') -> str str(bytes_or_buffer[, enc ...
- Python 工厂函数和内建函数
工厂函数 工厂函数都是类对象, 即当你调用他们时, 创建的其实是一个类实例 例如: str(), list(), tuple()... 内建函数 内建函数通常是python自定义的一些函数, 这些函数 ...
- Javascript我学之六对象工厂函数与构造函数
本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript ...
- python之工厂函数
python之工厂函数 本人也是小白一个,最近在学习python工厂函数时随便在网上搜了搜,发现许多人对工厂函数的理解存在误区,同时也是为了整理和记录自己的思路,写下本片博文. 工厂函数顾名思义就是一 ...
随机推荐
- Jave工具——servlet+jsp编程中mysql数据库连接及操作通用工具类
该工具类是在JavaWeb中连接mysql所用到的通用工具类 该类用于Java+Servlet的编程中,方便数据库的操作,连接,获取其列表值.下面是这个数据库操作类的通用方法,基本上能够用于类里面只含 ...
- Akka Stream之Graph
最近在项目中需要实现图的一些操作,因此,初步考虑使用Akka Stream的Graph实现.从而学习了下: 一.介绍 我们知道在Akka Stream中有三种简单的线性数据流操作:Source/Flo ...
- 模型搭建练习2_实现nn模块、optim、two_layer、dynamic_net
用variable实现nn.module import torch from torch.autograd import Variable N, D_in, H, D_out = 64, 1000, ...
- my -> mysql on duplicate key update使用总结
CREATE TABLE `t_duplicate` ( `a` int(11) NOT NULL, `b` int(255) DEFAULT NULL, `c` int(255) DEFAULT N ...
- 串口调试利器--Minicom配置及使用详解.md
因为现在电脑基本不配备串行接口,所以,usb转串口成为硬件调试时的必然选择.目前知道的,PL2303的驱动是有的,在dev下的名称是ttyUSB*. Minicom,是Linux下应用比较广泛的串口软 ...
- 如何在window上把你的项目提交到github
1.首先你需要在https://github.com/ 上注册一个账户 2.注册成功以后,你需要新建一个repository(储藏室),这个用来存放你要上传的项目 点击中间的带加号的图标就可以新建re ...
- 【Android】attr、style和theme
一.Attr 属性,风格样式的最小单元: Attr 的定义 在自定义 View 的时候,在 res/attrs.xml 文件中声明属性,而Android 系统的属性也是以同样的方式定义的.比如 lay ...
- php根据日期时间生成随机编码
订单.申请单之类的需要一个编码,通过下面方法可得 代码如下: $PNUM="PG" . date("YmdHis").rand(1000,9999);
- 2017.3.14 activiti实战--第二十章--REST服务
学习资料:<Activiti实战> 第二十章 REST服务 20.1 通信协议概述 略. 20.2 REST API概述 资源分类 资源基础URI 说明 Deployments manag ...
- 转: Gradle:Gradle入门
from: http://blog.csdn.net/p106786860/article/details/50422463