Flask_0x05 大型程序结构

0x1 项目结构

git checkout 7a

多文件Flask程序基本结构

多文件 Flask 程序的基本结构

|-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

Flask程序一般保存在app包中

migrations包含数据库迁移脚本

单元测试在tests包中

venv包含Python虚拟环境

requirements.txt列出所有依赖包

config.py 存储配置

manage.py 用于启动程序以及其他程序任务

0x2 配置选项

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
    MAIL_SERVER = ‘smtp.googlemail.com‘
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get(‘MAIL_USERNAME‘)
    MAIL_PASSWORD = os.environ.get(‘MAIL_PASSWORD‘)
    FLASKY_MAIL_SUBJECT_PREFIX = ‘[Flasky]‘
    FLASKY_MAIL_SENDER = ‘Flasky Admin <[email protected]>‘
    FLASKY_ADMIN = os.environ.get(‘FLASKY_ADMIN‘)

    @staticmethod
    def init_app(app):
        pass

class 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
}

基类Config包含通用配置,子类定义专用配置

0x3 程序包
  3.1 app
   程序包保存所有代码、模板、静态文件,这个包通常称为app

数据库模型和电子邮件支持函数保存为app/models.py和app/email.py

3.2 工厂函数

把创建程序实例移到可显式调用的工厂函数中,这样可以创建多个程序实例

app/__init__.py

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 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)

    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

create_app()就是程序的工厂函数,接受一个参数,是程序使用的配置名

配置类在config.py中定义,其中保存的配置可以使用Flask app.config配置对象提供的from_object()方法直接导入程序

配置对象则可以通过名字从config字典中选择

在之前创建的扩展对象上调用init_app()可以完成初始化过程

3.3 在蓝本中实现程序功能

蓝本可以定义路由,在蓝本中定义路由处于休眠状态,避免app.route定义路由不及时等问题

app/main/__init__.py:创建蓝本

from flask import Blueprint

main = Blueprint(‘main‘, __name__)

from . import views, errors

通过实例化一个Blueprint类对象可以创建蓝本,这个构造函数的两个必须指定的参数:

蓝本的名字和蓝本所在的包或模块,大多数情况第二个参数使用__name__变量

程序的路由在 app/main/views.py模块中,错误处理程序在app/main/errors.py模块中

导入这两个模块就能把路由和错误处理程序与蓝本关联起来(在app/main/__init__.py末尾导入)

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

要想注册程序全局的错误处理程序,必须使用app_errorhandler

app/main/views.py:蓝本中定义的程序路由

from flask import render_template, session, redirect, url_for, current_app
from .. import db
from ..models import User
from ..email import send_email
from . import main
from .forms import NameForm

@main.route(‘/‘, methods=[‘GET‘, ‘POST‘])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username=form.name.data)
            db.session.add(user)
            session[‘known‘] = False
            if current_app.config[‘FLASKY_ADMIN‘]:
                send_email(current_app.config[‘FLASKY_ADMIN‘], ‘New User‘,
                           ‘mail/new_user‘, user=user)
        else:
            session[‘known‘] = True
        session[‘name‘] = form.name.data
        return redirect(url_for(‘.index‘))
    return render_template(‘index.html‘,
                           form=form, name=session.get(‘name‘),
                           known=session.get(‘known‘, False))

在蓝本中url_for()用法不同,Flask为蓝本的全部端点加一个命名空间,命名空间就是蓝本的名字

所以视图函数index()注册的端点名是main.index,其URL使用url_for(‘main.index‘)获取

url_for()支持简写的端点形式,在蓝本中可以省略蓝本名,但跨蓝本的重定向的端点名必须带有命名空间

表单对象也要移到蓝本中,保存于 app/main/forms.py模块

0x4 启动脚本

顶级文件夹中的manage.py文件用于启动脚本

manage.py:启动脚本

#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role
from flask_script import Manager, Shell
from flask_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()

如果已经定义了环境变量FLASK_CONFIG,则从中读取配置名,否则使用默认配置

然后初始化Flask-Script、Flask-Migrate和为Python shell定义的上下文

脚本中加入shebang声明,可以通过./manage.py执行脚本

0x5 需求文件

程序中包含requirements.txt,用于记录所有依赖包及版本号

pip自动生成requirements.txt文件

(venv) $ pip freeze >requirements.txt

如果要创建这个虚拟环境的副本

(venv) $ pip install -r requirements.txt

0x6 单元测试

这个测试使用Python标准库中的unittest包编写

了解更多unittest包编写测试:https://docs.python.org/2/library/unittest.html

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‘])

setUp()方法创建一个测试环境,类似于运行中的程序

首先,使用测试配置创建程序,然后激活上下文,这样可确保能在测试中使用current_app

然后创建一个全新的数据库,以备不时之需,数据库和程序上下文在tearDown()方法中删除

第一个测试确保程序实例存在,第二个测试确保程序在测试配置中运行

若想把tests文件夹作为包使用,需要添加tests/__init__.py

manage.py:启动单元测试命令

@manager.command
def test():
    """Run the unit tests."""
    import unittest
    tests = unittest.TestLoader().discover(‘tests‘)
    unittest.TextTestRunner(verbosity=2).run(tests)

单元测试运行:

(venv) $ python manage.py test
test_app_exists (test_basics.BasicsTestCase) ... ok
test_app_is_testing (test_basics.BasicsTestCase) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.187s

OK

0x7 创建数据库

如果使用Flask-Migrate跟踪迁移,可使用如下命令创建数据表或升级到最新修订版:

(venv) $ python manage.py db upgrade
时间: 2024-11-09 02:12:49

Flask_0x05 大型程序结构的相关文章

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

尽管在单一脚本中编写小型Web 程序很方便,但这种方法并不能广泛使用.程序变复杂后,使用单个大型源码文件会导致很多问题.不同于大多数其他的Web 框架,Flask 并不强制要求大型项目使用特定的组织方式,程序结构的组织方式完全由开发者决定.在本节,我们将介绍一种使用包和模块组织大型程序的方式. 一.项目结构 Flask 程序的基本结构如下所示: |-blogs |-app/ |-templates/ |-static/ |-main/ |-__init__.py |-errors.py |-fo

单片机用定时器分配任务的程序结构总结

转载请注明本文地址:http://blog.sina.cn/dpool/blog/s/blog_6f2b6ba80101bwka.html?vt=4 http://blog.sina.cn/dpool/blog/s/blog_6f2b6ba80101bwka.html?vt=4本文是2013年写的,后来整理成了系统文章,请访问 http://nicekwell.net/ 查看单片机编程系列文章.以下是2013年原文:经过这几天做的程序,和以前做电子钟时的感悟,现在对单片机的整个程序结构做一下总结

ASP.NET MVC掉过的坑_MVC初识及MVC应用程序结构

APS.Net MVC 浅谈[转] 来自MSDN 点击访问 MVC 理论结构 模型-视图-控制器 (MVC) 体系结构模式将应用程序分成三个主要组件:模型.视图和控制器. ASP.NET MVC 框架提供用于创建 Web 应用程序的 ASP.NET Web 窗体模式的替代模式. ASP.NET MVC 框架是一个可测试性非常高的轻型演示框架,(与基于 Web 窗体的应用程序一样)它集成了现有的 ASP.NET 功能,如母版页和基于成员资格的身份验证. MVC 框架在 System.Web.Mvc

python3编程基础之一:程序结构

程序从程序入口进入,到程序执行结束,大体是按照顺序结构执行语句.函数或代码块,掌握程序的结构,有利于把握程序的主体框架. 1.顺序结构--最常见的结构 顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行.程序的执行严格按照程序语句在程序中出现的先后顺序执行,如果修改了程序语句的顺序,就会影响程序的执行结果.其实无论多么复杂的程序,大概都是按照顺序结构执行的. rad = int(input('please input the rad: '))

C#学习笔记二:C#程序结构

从最简单的HelloWorld开始入手,这是一个最低限度的C#程序结构. C# Hello World 示例 一个C#程序主要由以下几部分组成: 命名空间声明 一个类 类方法 类属性 一个Main方法 语句和表达式 注释 先看看下面的示例,将打印字的简单的代码 "Hello World": using System; namespace HelloWorldApplication { class HelloWorld { static void Main(string[] args)

黑马程序员---C基础3【变量的易错】【程序结构】【if语句】【Switch语句】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- [变量的易错] 1.变量为什么要初始化为0 int  sum,a=3: sum = sum+a 如果未初始化则会成为一个不确定的变量,结果也会不确定,容易出错. 2.不同类型的变量之间的转换 切记int  a=1,b=0:b=1-1.5:其中b为一个整型所有结果是保留整数部分的0,而不是-0.5,又因为0没有正负之分,所有保存结果为b=0: 3.关于Xcode的一个快速注释的插件 快捷键://

计算机病毒的定义、特征、程序结构、命名、传播与生命周期

一.定义:凡是人为编制的,干扰计算机正常运行并造成计算机软硬件故障, 甚至破坏计算机数据的可以自我复制的计算机程序或者指令集合 都是计算机病毒. 二.特征:非法性.隐藏性.潜伏性.可触发性.表现性.破坏性.传染性. 针对性.变异性.不可预见性. 隐藏性:缩小体积.潜入系统目录.标记坏簇.系统漏洞. 潜伏性:依附宿主程序伺机扩散. 破坏性:良性病毒.恶性病毒. 不可预见性:病毒超前于反病毒产品. 三.计算机病毒的程序结构 1> 引导部分:将病毒主题加载到内存,为传染部分做准备. 2> 传染部分:

C# 程序结构

C# 程序结构 在我们学习 C# 编程语言的基础构件块之前,让我们先看一下 C# 的最小的程序结构,以便作为接下来章节的参考. C# Hello World 实例 一个 C# 程序主要包括以下部分: 命名空间声明(Namespace declaration) 一个 class Class 方法 Class 属性 一个 Main 方法 语句(Statements)& 表达式(Expressions) 注释 让我们看一下上面程序的各个部分: 程序的第一行 using System; - using 

python基础(3)—— 程序结构

python和其他的编程语言一样,也有三种程序结构.顺序结构,选择结构,循环结构. 1.顺序结构 顺序结构按照顺序执行程序,不做过多解释. 2.选择结构     2.1 if 语句 if condition: expression 示例: [[email protected]]# cat if.py #!/usr/bin/env python if 3 < 5: print "3 less than 5" # 语句块里面可以是多个语句if 3 > 4: print &quo