Flask--项目结构
来源:互联网 发布:js 编辑:程序博客网 时间:2024/05/21 07:26
Flask程序的基本结构
先来一张Flask程序的基本结构图:
1. 配置选项文件
config.py 文 件的内容:
import osbasedir = os.path.abspath(os.path.dirname(__file__))class Config: SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' SQLALCHEMY_COMMIT_ON_TEARDOWN = True #the database pagination FLASKY_POSTS_PER_PAGE = 20 @staticmethod def init_app(app): passclass DevelopmentConfig(Config): DEBUG = True SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')class ProductionConfig(Config): SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ 'sqlite:///' + os.path.join(basedir, 'data.sqlite')config = { 'development': DevelopmentConfig, 'testing': TestingConfig, 'production': ProductionConfig, 'default': DevelopmentConfig}
为了让配置方式更灵活且更安全,某些配置可以从环境变量中导入。例如,SECRET_KEY
的值,这是个敏感信息,可以在环境中设定,但系统也提供了一个默认值,以防环境中没有定义。
配置类可以定义 init_app() 类方法,其参数是程序实例。在这个方法中,可以执行对当前 环境的配置初始化。现在,基类 Config 中的 init_app() 方法为空。
2. 使用工厂函数,创建程序实例
在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提高测试覆盖度,必须在不同的配置环境中运行程序。
这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例,这些实例有时在测试中非常有用。程序的工厂函数在 app 包的构造文件中定义。
构造文件导入了大多数正在使用的 Flask 扩展。由于尚未初始化所需的程序实例,所以没有初始化扩展,创建扩展类时没有向构造函数传入参数。create_app() 函数就是程序的工 厂函数,接受一个参数,是程序使用的配置名。配置类在 config.py 文件中定义,其中保存的配置可以使用 Flask app.config 配置对象提供的 from_object() 方法直接导入程序。
程序创建并配置好后,就能初始化 扩展了。在之前创建的扩展对象上调用 init_app() 可以完成初始化过程。
说白了,这里的工厂函数的作用就是,调用者可以通过一个函数调用创建Flask实例对象,不要跟随着程序的运行立即就创建Flask实例对象。让调用者有机会做进一步的配置。
from flask import Flaskfrom flask_bootstrap import Bootstrapfrom flask_sqlalchemy import SQLAlchemyfrom config import configbootstrap = Bootstrap()db = SQLAlchemy()def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) bootstrap.init_app(app) db.init_app(app) #附加路由和自定义的错误页面 return app
现在工厂函数创建的程序还不完整,因为没有路由和自定义的错误页面处理程序。
假设在上面增加的路由是下面的代码:
# add the app route and error handler function@app.route('/')def index(): return '<h1>Hello, World!</h1>'
这时的manage.py
文件脚本为:
#!/usr/bin/env python# -*- coding: utf-8 -*-import osfrom flask_script import Manager, Serverfrom app import create_appapp = create_app(os.getenv('FLASK_CONFIG') or 'default')manager = Manager(app)manager.add_command("runserver", Server(host="0.0.0.0", port=8081, use_debugger=True))if __name__ == "__main__": manager.run()
工程的目录结构为:
这里仍然有问题,那就是视图函数在__init__.py
中,并没有独立到views.py
文件中。
- 直接粗暴的把
__init__.py
中的绑定路由放到一个views.py
的文件中。这种方案是不可行的,因为路由的绑定使用的是app.route
这个装饰器,这时的app
一定要是一个Flask
实例对象。如果直接把路由绑定写到views.py
中,在这个文件中没有Flask
实例对象app
。 在
views.py
的头部import
一个app
实例。注意由于工厂函数的引入,在__init__.py
中是没有Flask对象实例的,有的仅仅是一个工厂函数,真正拥有Flask实例对象的是外层的manage.py
,但是这个文件属于工程的配置文本,不属于真正的工程文件。如果,在
__init__.py
中不使用工厂函数,直接创建Flask
实例对象,方案2从__init__.y
文件中import app
是可行的。使用蓝本,这是标准的解决办法。
3. 在蓝本中实现程序功能
转换成程序工厂函数的操作让定义路由变复杂了。在单脚本程序中,程序实例存在于全 局作用域中,路由可以直接使用 app.route 修饰器定义。但现在程序在运行时创建,只有调用 create_app() 之后才能使用 app.route 修饰器。但是create_app的调用者是项目的配置脚本,虽然技术实现上可以在这里配置路由,但是从项目的结构上说不能在这里添加路由。
和路由 一样,自定义的错误页面处理程序也面临相同的困难,因为错误页面处理程序使用 app. errorhandler 修饰器定义。
蓝本和程序类似,也可以定义路由。不同的 是,在蓝本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真正成为程序 的一部分。使用位于全局作用域中的蓝本时,定义路由的方法几乎和单脚本程序一样。
和程序一样,蓝本可以在单个文件中定义,也可使用更结构化的方式在包中的多个模块中 创建。为了获得最大的灵活性,程序包中创建了一个子包,用于保存蓝本。
蓝本的创建
在app/main/__init__.py
中创建蓝本:
from flask import Blueprintmain = Blueprint('main', __name__)from . import views, errors
通过实例化一个 Blueprint
类对象可以创建蓝本。这个构造函数有两个必须指定的参数: 蓝本的名字和蓝本所在的包或模块。和程序一样,大多数情况下第二个参数使用 Python
的 __name__
变量即可。
程序的路由保存在包里的 app/main/views.py
模块中,而错误处理程序保存在 app/main/ errors.py
模块中。导入这两个模块就能把路由和错误处理程序与蓝本关联起来。
注意,这 些模块在
app/main/__init__.py
脚本的末尾导入,这是为了避免循环导入依赖,因为在views.py
和errors.py
中还要导入蓝本main
。
蓝本的注册
蓝本在app/_init_.py
中的工厂函数 create_app() 中注册到程序上:
def create_app(config_name): # create the app from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app
蓝本内部路由的配置
app/main/errors.py
文件蓝本中的错误处理程序:
from flask import render_templatefrom . import main@main.app_errorhandler(404)def page_not_found(e): return render_template('404.html'), 404@main.app_errorhandler(500)def internal_server_error(e): return render_template('500.html'), 500
在蓝本中编写错误处理程序稍有不同,如果使用 errorhandler 修饰器,那么只有蓝本中的错误才能触发处理程序。要想注册程序全局的错误处理程序,必须使用 app_errorhandler。
app/main/views.py
文件蓝本中定义的程序路由:
from datetime import datetimefrom flask import render_template, session, redirect, url_forfrom . import mainfrom .forms import NameFormfrom .. import dbfrom ..models import User@main.route('/', methods=['GET', 'POST'])def index(): form = NameForm() if form.validate_on_submit(): # ... return redirect(url_for('.index')) return render_template( 'index.html', form=form, name=session.get('name'), known=session.get('known', False), current_time=datetime.utcnow())
在蓝本中编写视图函数主要有两点不同:
第一:和前面的错误处理程序一样,路由修饰器 由蓝本提供;
第二:url_for()
函数的用法不同。你可能还记得,url_for()
函数的第一 个参数是路由的端点名,在程序的路由中,默认为视图函数的名字。例如,在单脚本程序 中,index()
视图函数的 URL
可使用 url_for('index')
获取。
在蓝本中就不一样了,Flask
会为蓝本中的全部端点加上一个命名空间,这样就可以在不同的蓝本中使用相同的端点名定义视图函数,而不会产生冲突。命名空间就是蓝本的名字 (Blueprint
构造函数的第一个参数),所以视图函数 index()
注册的端点名是 main.index
,其 URL 使用 url_for('main.index')
获取。
url_for()
函数还支持一种简写的端点形式,在蓝本中可以省略蓝本名,例如 url_for('. index')
。在这种写法中,命名空间是当前请求所在的蓝本。这意味着同一蓝本中的重定向 可以使用简写形式,但跨蓝本的重定向必须使用带有命名空间的端点名。
为了完全修改程序的页面,表单对象也要移到蓝本中,保存于
app/main/forms.py
模块。
- Flask--项目结构
- flask-项目结构
- 【Flask】在PyCharm上组织Flask大型项目文件结构
- [python3.6 flask web学习]Flask项目目录结构
- flask结构
- Flask基本结构
- Flask代码结构总结
- 仿照django的urls风格和模块化结构的flask项目(Django-Style URL Patterns for Flask)
- Flask学习笔记02--Flask基本结构
- Flask 项目实战教程。。。
- Flask 项目实战教程。。。
- ubuntu部署flask项目
- flask框架项目搭建
- flask入门项目
- Flask项目配置文件
- Flask项目文件目录
- Flask基本结构(一)
- Flask 多文件基本结构
- MATLAB Primitive Types
- 骨肉至亲
- wxPython for mac 安装
- 要怎样努力,才能成为很厉害的人?
- 【u035】奶牛的电信
- Flask--项目结构
- 一个不错的按钮检测程序
- 【record】#10
- 【record】10.30..11.6
- Android7.0 Ninja编译原理
- bzoj 3787: Gty的文艺妹子序列 分块+树状数组
- 调整版PHP的CURL类(POST、GET、PUT、DELETE)
- 硬件设计笔记の运算放大器
- CDOEVS 2980 买帽子