Flask:工厂函数和蓝本

Posted 一张红枫叶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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__.pyconfig.py,run.pymodel_sqlite.py,manger.py

三个文件的作用分别如下,

__init__.py其中就包含工厂函数,是定义工厂函数的地方

config.py 和之前的配置选项一样,定义各种的配置选项

run.py:主程序.

model_sqlite.py是定义数据模型的地方

manger.py 是配置数据迁移的文件

其中还包含main package. main package包含__init__.pyviews.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的绑定.在这里绑定了bootstrapdb.最终返回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_folderstatic_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__.pycreate_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 web开发》笔记5:大型程序的结构&用户认证Flask-Login

Flask入门flask-script 蓝本 钩子函数

flask 模板引擎

Haytham个人博客开发日志 -- Flask+Vue基于token的登录状态与路由管理

flask使用工厂函数后怎么用uwsgi启动?

Flask框架工厂函数用法实例分析