把程序模块化。
最终结构:
|-flasky
|-app/
|-templates/
|-static/
|-main/
|-__init__.py
|-errors.py
|-forms.py
|-views.py
|-__init__.py
|-email.py
|-models.py
|-migrations/
|-tests/
|-__init__.py
|-test*.py
|-venv/
|-requirements.txt
|-config.py
|-manage.py
- 程序在app中。
- config.py存储设置
- manage.py启动程序
7.2 配置选项
开发,测试,生产使用不同的数据库.
放在根目录config.py
7.3 程序文件夹
程序代码分门别类放在app/下,templates和static也放在下面
数据库和电子邮件支持放在app/models.py 和 app/email.py。
7.3.1 application factory 工厂函数
单个文件程序一旦运行起来就无法再对程序进行修改了,也就是不能在程序运行的时候动态修改配置。
为了能动态修改配置(程序运行时候),需要延迟创建程序实例,把创建过程移到可显式调用的工厂函数中。这种方法不仅可以给脚本留出配置程序的时间,还能够创建多个程序实例,这些实例有时在测试中非常有用。程序的工厂函数在 app 包的构造文件中定义.
这些是flask框架提供的:
- config配置对象提供的下面两个方法
- from_object导入config中的配置类
- init_app初始化
构造文件:app/init.py
from flask import Flask, render_template
from flask.ext.bootstrap import Bootstrap
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from config import config
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
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)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
# 附加路由和自定义的错误页面(见下节)
return app
7.3.2 蓝本blueprint定义路由
在蓝本中定义的路由处于休眠状态,直到蓝本init到程序上后,路由才真正成为程序的一部分。和程序一样,蓝本可以在单个文件中定义,也可使用更结构化的方式在包中的多个模块中创建。为了获得最大的灵活性,程序包中创建了一个子包,用于保存蓝本。
app/main/init.py :创建蓝本
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
‘main’, name: 蓝本的名字main和蓝本所在的包或模块.
app/init.py中加入:
# 附加路由和自定义的错误页面
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
程序的路由保存在包里的 app/main/views.py 模块中,而错误处理程序保存在 app/main/errors.py 模块中。导入这两个模块就能把路由和错误处理程序与蓝本关联起来。注意,这些模块在app/main/init.py 脚本的末尾导入,这是为了避免循环导入依赖,因为在views.py 和 errors.py 中还要导入蓝本 main 。
app/main/errors.py:
from flask import render_template
from . 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 datetime
from flask import render_template, session, redirect, url_for
from . import main
from .forms import NameForm
from .. import db
from ..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’) 获取。
简写为.index就是当前请求所在的蓝本。
表单对象也要放到蓝本中,app/main/forms.py
7.4 启动脚本
根目录下的manage.py文件用于启动程序
#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role
from flask.ext.script import Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
第一行叫shebang声明。可以直接./manage.py
7.5 用到的包
生成requirements
(venv) $ pip freeze >requirements.txt
如果你要创建这个虚拟环境的完全副本,可以创建一个新的虚拟环境,并在其上运行以下
命令:
(venv) $ pip install -r requirements.txt
Flask==0.10.1
Flask-Bootstrap==3.0.3.1
Flask-Mail==0.9.0
Flask-Migrate==1.1.0
Flask-Moment==0.2.0
Flask-SQLAlchemy==1.0
Flask-Script==0.6.6
Flask-WTF==0.9.4
Jinja2==2.7.1
Mako==0.9.1
MarkupSafe==0.18
SQLAlchemy==0.8.4
WTForms==1.0.5
Werkzeug==0.9.4
alembic==0.6.2
blinker==1.3
itsdangerous==0.23
7.6 单元测试
执行 git checkout 7a 签出程序的这个版本。为确保安装了所有依赖包,还需执行 pip install -r requirements.txt 命令.
/tests/test_basics.py
import unittest #for python test
from flask import current_app
from app import create_app, db
class BasicsTestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_app_exists(self):
self.assertFalse(current_app is None)
def test_app_is_testing(self):
self.assertTrue(current_app.config['TESTING'])
在manage.py中设置了命令行运行单元测试
7.7 创建数据库
如果使用 Flask-Migrate 跟踪迁移,可使用如下命令创建数据表或者升级到最新修订版本:
(venv) $ python manage.py db upgrade
设置环境变量
查看:
$ export
/manage.py中os.getenv(‘FLASK_CONFIG’)
/config.py中os.environ.get()