zoukankan      html  css  js  c++  java
  • 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 <flasky@example.com>'
        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
  • 相关阅读:
    自动化原理
    Appium 用途和特点
    接口测试
    测试环境部署
    总结一下,selenium 自动化流程如下
    Qt---tcp之网络通信
    java的接口与抽象类
    Leetcode---每日一题之56合并区间
    java与c++的正则表达式的小总结
    数据结构学习之线索二叉树(java/c++版)
  • 原文地址:https://www.cnblogs.com/trojan-z/p/6362255.html
Copyright © 2011-2022 走看看