一.程序包

  程序包用来保存程序的所有代码、模板和静态文件。我们可以把这个包直接称为app(应用),如果有需求,也可使用一个程序专用名字。templates 和static 文件夹是程序包的一部分,因此这两个文件夹被移到了app 中。数据库模型和电子邮件支持函数也被移到了这个包中,分别保存为app/models.py 和app/email.py。

使用程序工厂函数

  在单个文件中开发程序很方便,但却有个很大的缺点,因为程序在全局作用域中创建,所以无法动态修改配置。运行脚本时,程序实例已经创建,再修改配置为时已晚。这一点对单元测试尤其重要,因为有时为了提高测试覆盖度,必须在不同的配置环境中运行程序。

  这个问题的解决方法是延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例,这些实例有时在测试中非常有用。程序的工厂函数在app 包的构造文件中定义,如下所示:

from flask import Flask
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_pagedown import PageDown
from config import config bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
pagedown = PageDown() login_manager = LoginManager()
login_manager.login_view = 'auth.login' 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)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
login_manager.init_app(app)
pagedown.init_app(app)
...
return app

  构造文件导入了大多数正在使用的Flask 扩展。由于尚未初始化所需的程序实例,所以没有初始化扩展,创建扩展类时没有向构造函数传入参数。create_app() 函数就是程序的工厂函数,接受一个参数,是程序使用的配置名。配置类在config.py 文件中定义,其中保存
的配置可以使用Flask app.config 配置对象提供的from_object() 方法直接导入程序。至于配置对象,则可以通过名字从config 字典中选择。程序创建并配置好后,就能初始化扩展了。在之前创建的扩展对象上调用init_app() 可以完成初始化过程。

在蓝本中实现程序功能

  转换成程序工厂函数的操作让定义路由变复杂了。在单脚本程序中,程序实例存在于全局作用域中,路由可以直接使用app.route 修饰器定义。但现在程序在运行时创建,只有调用create_app() 之后才能使用app.route 修饰器,这时定义路由就太晚了。和路由一样,自定义的错误页面处理程序也面临相同的困难,因为错误页面处理程序使用app.errorhandler 修饰器定义。

  幸好Flask 使用蓝本提供了更好的解决方法。蓝本和程序类似,也可以定义路由。不同的是,在蓝本中定义的路由处于休眠状态,直到蓝本注册到程序上后,路由才真正成为程序的一部分。使用位于全局作用域中的蓝本时,定义路由的方法几乎和单脚本程序一样。和程序一样,蓝本可以在单个文件中定义,也可使用更结构化的方式在包中的多个模块中创建。为了获得最大的灵活性,程序包中创建了一个子包,用于保存蓝本。下面的例子是这个子包的构造文件,蓝本就创建于此。

app/main/__init__.py:创建蓝本
from flask import Blueprint
main = 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。

  蓝本在工厂函数create_app() 中注册到程序上:

def create_app(config_name):
from .main import main as main_blueprint
app.register_blueprint(main_blueprint) from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth') from .api import api as api_blueprint
app.register_blueprint(api_blueprint, url_prefix='/api/v1') return app

  在蓝本中编写错误处理程序稍有不同,如果使用errorhandler 修饰器,那么只有蓝本中的错误才能触发处理程序。要想注册程序全局的错误处理程序,必须使用app_errorhandler 

from flask import render_template, request, jsonify
from . import main @main.app_errorhandler()
def forbidden(e):
if request.accept_mimetypes.accept_json and \
not request.accept_mimetypes.accept_html:
response = jsonify({'error': 'forbidden'})
response.status_code =
return response
return render_template('403.html'),

  在蓝本中编写视图函数主要有两点不同:第一,和前面的错误处理程序一样,路由修饰器由蓝本提供;第二,url_for() 函数的用法不同。你可能还记得,url_for() 函数的第一个参数是路由的端点名,在程序的路由中,默认为视图函数的名字。例如,在单脚本程序
中,index() 视图函数的URL 可使用url_for('index') 获取。在蓝本中就不一样了,Flask 会为蓝本中的全部端点加上一个命名空间,这样就可以在不同的蓝本中使用相同的端点名定义视图函数,而不会产生冲突。命名空间就是蓝本的名字(Blueprint 构造函数的第一个参数),所以视图函数index() 注册的端点名是main.index,其URL 使用url_for('main.index') 获取。

  url_for() 函数还支持一种简写的端点形式,在蓝本中可以省略蓝本名,例如url_for('.index')。在这种写法中,命名空间是当前请求所在的蓝本。这意味着同一蓝本中的重定向可以使用简写形式,但跨蓝本的重定向必须使用带有命名空间的端点名。

@main.route('/', methods=['GET', 'POST'])
def index():
form = PostForm()
if current_user.can(Permission.WRITE) and form.validate_on_submit():
post = Post(body=form.body.data,
author=current_user._get_current_object())
db.session.add(post)
db.session.commit()
return redirect(url_for('.index'))

    

Flask从入门到精通之大型程序的结构二的更多相关文章

  1. Flask从入门到精通之大型程序的结构一

    尽管在单一脚本中编写小型Web 程序很方便,但这种方法并不能广泛使用.程序变复杂后,使用单个大型源码文件会导致很多问题.不同于大多数其他的Web 框架,Flask 并不强制要求大型项目使用特定的组织方 ...

  2. Flask从入门到精通之flask程序入门

    初始化 所有Flask程序都必须创建一个程序实例,Web服务器使用一种名为Web服务器网关接口的的协议(WSGI),把接收自客户端的所有请求转发给这个对象处理.程序实例是Flask类的对象,使用下面代 ...

  3. [ Python ] Flask 基于 Web开发 大型程序的结构实例解析

    作为一个编程入门新手,Flask是我接触到的第一个Web框架.想要深入学习,就从<FlaskWeb开发:基于Python的Web应用开发实战>这本书入手,本书由于是翻译过来的中文版,理解起 ...

  4. Flask从入门到精通之Flask-Bootstrap的使用

    Bootstrap(http://getbootstrap.com/)是Twitter 开发的一个开源框架,它提供的用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代Web 浏 ...

  5. Flask从入门到精通之使用Flask-Migrate实现数据库迁移

    在开发程序的过程中,你会发现有时需要修改数据库模型,而且修改之后还需要更新数据库.仅当数据库表不存在时,Flask-SQLAlchemy 才会根据模型进行创建.因此,更新表的唯一方式就是先删除旧表,不 ...

  6. Flask从入门到精通之使用Flask-SQLAlchemy管理数据库

    Flask-SQLAlchemy 是一个Flask 扩展,简化了在Flask 程序中使用SQLAlchemy 的操作.SQLAlchemy 是一个很强大的关系型数据库框架,支持多种数据库后台.SQLA ...

  7. Flask从入门到精通之Flash消息

    请求完成后,有时需要让用户知道状态发生了变化.这里可以使用确认消息.警告或者错误提醒.一个典型例子是,用户提交了有一项错误的登录表单后,服务器发回的响应重新渲染了登录表单,并在表单上面显示一个消息,提 ...

  8. Flask从入门到精通之重定向和用户会话

    最新版的hello.py 存在一个可用性问题.用户输入名字后提交表单,然后点击浏览器的刷新按钮,会看到一个莫名其妙的警告,要求在再次提交表单之前进行确认.之所以出现这种情况,是因为刷新页面时浏览器会重 ...

  9. Flask从入门到精通之跨站请求伪造保护

    默认情况下,Flask-WTF 能保护所有表单免受跨站请求伪造(Cross-Site Request Forgery,CSRF)的攻击.恶意网站把请求发送到被攻击者已登录的其他网站时就会引发CSRF ...

随机推荐

  1. sdk接入

    文档 http://blog.csdn.net/chenjie19891104/article/details/42217281 视频: https://chuanke.baidu.com/v2869 ...

  2. 8个设计师必看的免费UI图标设计资源站

    图标是我们日常APP及网页设计过程中必不可少的元素之一,通过小小的图标,可以快速方便的实现视觉引导和功能划分.在创作时,我们需要寻找各种各样的图标来满足自己的设计需求,非常浪费时间和精力.今天,小编给 ...

  3. echarts 使用配置模式(含事件)

    <!-- 引入echarts UMD 环境--> <script src="js/echarts/build/dist/echarts.js"></s ...

  4. struts2乱码问题

    简介:做了个功能,用的struts2,表单提交到后台,接收后打印出来的数据乱码.   解决步骤: 1. struts.xml中配置<constant name="struts.i18n ...

  5. phoenix错误

    spark集群与phoenix进行数据请求时报错: 2018-06-15 17:13:30,158 INFO - Starting task 15.3 in stage 116.0 (TID 6832 ...

  6. 2018.09.16 spoj104Highways (矩阵树定理)

    传送门 第一次写矩阵树定理. 就是度数矩阵减去邻接矩阵之后得到的基尔霍夫矩阵的余子式的行列式值. 这个可以用高斯消元O(n3)" role="presentation" ...

  7. struts2从浅至深(四)下载文件

    1.创建下载文件动作类 2.配置struts 3.提供一个下载链接 4.下载页面 为什么文件名是链接名 只是以链接名显示,但文件的本身是个图片秩序改掉后缀名就可以了

  8. 几个经典的数学库之一学习---VCGlib(1)

    1. VCG Libary是Visulization and Computer Graphics Libary(可视化与计算机图形学库)的缩写,是一个开源的C++模板库,用于三角网格和四面体网格的控制 ...

  9. Amazon成本和产出的衡量方式

    Amazon用一种T-Shirt Size 估计的方式来做项目. 产品经理会对每一条需求评估上业务影响力的尺寸,如:XXXL 影响一千万人以上或是可以占到上亿美金的市场,XXL,影响百万用户或是占了千 ...

  10. hdu 5023 线段树+状压

    http://acm.hdu.edu.cn/showproblem.php?pid=5023 在片段上着色,有两种操作,如下: 第一种:P a b c 把 a 片段至 b 片段的颜色都变为 c . 第 ...