zoukankan      html  css  js  c++  java
  • 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)

  • 相关阅读:
    团队博客-会议之初
    5.2 个人作业2
    5.1 如何利用Intellij Idea搭建python编译运行环境
    4.27 python神器——Anaconda的安装与优化配置
    4.26 AlertDialog(对话框)详解
    4.25 xmapp启动mysql出现Error: MySQL shutdown unexpectedly.
    4.24 Android Studio下应用签名的方法以及获取 MD5、SHA1(签名)、SHA256 值
    4.23 2020.2新版本idea创建javaEE web文件
    4.22 Android studio 通过获取验证码用户登陆成功
    4.21 Android 记住密码和自动登录界面的实现(SharedPreferences 的用法)
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/8447589.html
Copyright © 2011-2022 走看看