Flask(7)-大型程序的结构
2016-05-30 10:05
218 查看
项目结构
|-flasky |-app/ #所有flask程序 |-templates/ #模板 |-static/ #css文件 |-models.py #数据库模型 |-email.py #email |-__init__.py #程序包的构造函数,工厂函数在其中定义 |-main/ |-__init__.py |-errors.py |-views.py |-migrations/ |-tests/ |-venv/ |-requirements.txt |-config.py |-manage.py
四个顶级文件夹:
Flask程序一般保存在名为app的包中;
migrations文件夹包含数据库迁移脚本;
单元测试编写在tests包中;
venv包含虚拟环境。
同时还创建一些新文件:
requirements.txt列出所有依赖包;
config.py存储配置;
manage.py用于启动程序以及其他的程序任务。
配置选项
config.py: 程序的配置import os basedir = 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 FLASKY_MAIL_SUBJECT_PREFIX = '[FLASKY]' FLASKY_MAIL_SENDER = 'Flasy Admin <flasky@example.com>' FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN') @staticmethod def init_app(app) pass class DevelopmentConfig(Config): DEBUG = True MAIL_SERVER = 'smtp.googlemail.com' MAIL_PORT = 587 MAIL_USE_TLS = True MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_PASSWORD = os.environ. 4000 get('MAIL_PASSWORD') SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_RUL') or \'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite') class TestingConfig(Config): TESTING = True SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_RUL') or \'sqlite:///' + os.path.join(basedir, 'data-test.sqlite') class ProductionConfig(Config): SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_RUL') or \'sqlite:///' + os.path.join(basedir, 'data.sqlite') config = { 'development': DevelopmentConfig 'testing': TestingConfig 'production': ProductionConfig 'default': DevelopmentConfig }
程序包
程序包包含模板、代码、静态文件。templates和static文件被保存在app中,数据库模型和电子邮件支持分别被保存为app/models.py和app/email.py。
使用程序工厂函数
单个文件中开发程序有个问题,因为程序在全局作用域中创建,因此无法动态修改配置。解决这个问题的方法是延迟创建程序实例,把创建实例的过程移到可显示调用的工厂函数中。这种方法可以给脚本留出配置程序的时间,还可以创建多个程序实例。
示例 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() # 尚未初始化所需的程序实例(即无app = Flask(__name__)),所以没有初始化扩展,即创建扩展类时没有传入参数。 def create_app(config_name): #工厂函数,接收程序使用的配置名作为参数 app = Flask(__name__) #初始化程序实例 app.config.form_object(config[config_name]) #通过app.config配置对象的form_object方法直接导入配置 config[config_name].init_app(app) #初始化配置 bootstrap.init_app(app) #初始化 mail.init_app(app) moment.init_app(app) db.init_app(app) # 附加路由和自定义的错误页面 return app #工厂函数返回创建的程序实例
什么是配置名、配置对象、配置类
在蓝本中实现程序功能
转换成程序工厂函数的操作让定义路由变得复杂,因为现在程序在运行时创建,只有调用create_app()之后才能使用app.route修饰器,这时定义路由就太晚了。Flask使用蓝本提供更好方法。蓝本也可以定义路由,但蓝本中定义的路由出于休眠状态,知道蓝本注册到程序上时,路由才真正成为程序的一部分。使用全局作用域中的蓝本和单脚本一样。
和程序一样,蓝本可以在单个文件中定义,也可以使用更结构化的方式在包的多个模块中创建。为获得最大的灵活性,程序包中创建一个子包,用于保存蓝本。
示例 app/main/__init__.py: 创建蓝本
from flask import Blueprint main = Blueprint('main', __name__) #接收两个参数,蓝本的名字和蓝本所在包或模块的名字 from . import views, errors
程序的路由和错误处理程序分别保存在app/main/views.py模块和app/main/errors.py模块中。导入这两个模块就可以把这两者和蓝本关联起来。注意在末尾导入,避免循环导入依赖。
蓝本在工厂函数create_app()中注册到程序上:
示例 app/__init__.py: 注册蓝本 def create_app(config_name): # ... from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app
错误处理程序:
示例 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 .froms import NameForm from .. import db from ..models import User @main.route('/', methods=['GET', 'POST']) def index(): name = NameForm() if form.validate_on_submit(): # ... return redirect(url_for('.index')) return render_template('index.html', from=from, name=session.get('name'), known=session.get('known', False), current_time=datetime.utcnow())
蓝本中编写视图函数有两点不同:
和之前错误处理程序一样,路由修饰器由蓝本提供
url_for()函数用法不同。url_for()函数的第一个参数是路由的端点名,Flask为蓝本中的所有端点增加一个命名空间(蓝本的名字),所以视图函数的端点名为main.index,在蓝本中可以省略蓝本名。
启动脚本
顶级文件夹中的manage.py文件用于启动程序。示例 manage.py: 启动脚本 #!/user/bin/env python import os from app import create_app, db from app.models import Role, User from flask.ext.scripts 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()
这个脚本先创建程序。
需求文件
程序中必须包含一个requirements.txt文件,用于记录所有依赖包及其精确的版本号。单元测试
示例 tests/test_basics.py: 单元测试 import unittest 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'])
相关文章推荐
- 工作中的思考
- python批量查询网站名称
- 使用 recyclerView 布局显示不合理的问题
- Eclipse Plug-in Hello world
- ENVI二次开发时ENVI_GET_DATA等函数的编译报错问题
- QT gdb安装
- android 导入gradle项目The project is using an unsupported version of Gradle.
- nginx重点优化合集一
- 统计单词个数(26)
- java学习:java 基础语法你都了解清楚了吗?
- SQL_从星期一到星期六自动打卡SQL代码
- php 判断文件或目录是否存在
- Mysql 查看、创建、更改 数据库和表
- 悠然一指,点“识”成金
- [51Nod算法马拉松14 F] 斐波那契树
- Struts2开发基本步骤
- 快排,二分查找
- LINUX连接mysql数据库
- JavaScript学习--Item13 理解 prototype, getPrototypeOf 和__proto__
- Hibernate配置文件详解