zoukankan      html  css  js  c++  java
  • 7. Flask 大型程序的结构

    7.1 项目结构

    该结构是根据<<FlaskWeb开发:基于Python的Web应用开发实战>> 第7章中推荐的项目结构搭建,是一种使用包和模块组织大型程序的方式。

    这种结构有4个顶级的文件夹:

    • Flask 主程序(功能业务代码)一般都保存在app包中;
    • migrations 文件夹包含数据库迁移脚本;
    • 单元测试编写在test包中
    • venv文件夹包含Python虚拟环境

    同时还创建了一些新文件:

    • requirements.txt 列出了所有的依赖包,便于在其他业务环境中生成相同的虚拟环境;
    • config.py 由于存储配置
    • manage.py 用于启动程序及其他的程序任务(本例中加入了Shell,MigrateCommand)

    7.2 配置选项

    我们给程序设定了多个配置,开发,测试,生产环境。

    config.py

     1 import os
     2 
     3 basedir = os.path.abspath(os.path.dirname(__file__))
     4 
     5 
     6 class Config:
     7     SECRET_KEY = os.environ.get('SECRET_KEY') or 'Hard to guess string!'
     8     SQLALCHEMY_COMMIT_ON_TEARDOWN = True
     9     SQLALCHEMY_TRACK_MODIFICATIONS = True
    10     FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
    11     FLASKY_MAIL_SENDER = 'zhangjin@9158.com'
    12     FLASK_ADMIN = os.environ.get('FLASKY_ADMIN')
    13 
    14     @staticmethod
    15     def init_app(app):
    16         pass
    17 
    18 
    19 class DevelopmentConfig(Config):
    20     DEBUG = True
    21     MAIL_SERVER = 'mail.9158.com'
    22     MAIL_PORT = 587
    23     MAIL_USE_TLS = True
    24     MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    25     MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    26     SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URI') or 'sqlite:///' + os.path.join(basedir,
    27                                                                                                 'data-dev.sqlite')
    28 
    29 
    30 class TestingConfig(Config):
    31     TESTING = True
    32     SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URI') or 'sqlite:///' + os.path.join(basedir,
    33                                                                                                  'data-test.sqlite')
    34 
    35 
    36 class ProductionConfig(Config):
    37     SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
    38 
    39 
    40 config = {
    41     'development': DevelopmentConfig,
    42     'testing': TestingConfig,
    43     'production': ProductionConfig,
    44     'default': DevelopmentConfig
    45 }

    基类Config包含通用配置,子类分别定义专用的配置。

    在3个子类中,SQLALCHEMY_DATABASE_URI变量都被指定了不同的值,这样程序就可以在不同的配置中运行,每个环境都使用指定不同的数据库。

    在配置最后,config字典还注册了不同的环境。

    7.3 程序包

    程序包用来保存所有的代码,模板和静态文件。我们可以把这个包直接成为app,如果有需求也可以使用专有的名字;templates,static,models.py,mail.py都是这个包的一部分。

    7.3.1 使用程序工厂函数

    app/__init__.py

     1 from flask import Flask, render_template
     2 from flask_bootstrap import Bootstrap
     3 from flask_mail import Mail
     4 from flask_moment import Moment
     5 from flask_sqlalchemy import SQLAlchemy
     6 from config import config
     7 
     8 bootstrap = Bootstrap()
     9 mail = Mail()
    10 moment = Moment()
    11 db = SQLAlchemy()
    12 
    13 
    14 def create_app(config_name):
    15     app = Flask(__name__)
    16     app.config.from_object(config[config_name])
    17     config[config_name].init_app(app)
    18 
    19     bootstrap.init_app(app)
    20     mail.init_app(app)
    21     moment.init_app(app)
    22     db.init_app(app)
    23 
    24     from .main import main as main_blueprint
    25     app.register_blueprint(main_blueprint)
    26     return app

    构造文件导入了大多数正在使用的Flask扩展,。由于尚未初始化所需的程序实例,所以没有初始化拓展,创建扩展类时没有传入参数。create_app函数就是程序的工厂函数,接收一个参数,是程序使用的配置名。程序的配置在config.py中定义,可直接使用Flask app.config中提供的from_object()方法直接导入程序。

    7.3.2 使用蓝本实现程序功能

    蓝本和程序类似,也可以定义路由。不同的是,在蓝本中定义的路由处于休眠状态,直到蓝本被注册到程序上面,录有才真正成为程序的一部分。

    创建蓝本:

    app/main/__init__.py

    from flask import Blueprint
    
    
    main = Blueprint('main', __name__)
    
    
    from . import views, errors

    注册蓝本:

    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/main/views.py

     1 from datetime import datetime
     2 from flask import render_template, session, redirect, url_for, flash
     3 
     4 from . import main
     5 from .forms import NameForm
     6 from .. import db
     7 from ..models import User
     8 
     9 
    10 @main.route('/', methods = ['GET', 'POST'])
    11 def index():
    12     form = NameForm()
    13     if form.validate_on_submit():
    14         user = User.query.filter_by(username=form.name.data).first()
    15         if user is None:
    16             user = User(username=form.name.data)
    17             db.session.add(user)
    18             session['known'] = False
    19         else:
    20             session['known'] = True
    21         old_name = session.get('name')
    22         if old_name is not None and old_name != form.name.data:
    23             flash('Look like you have changed your name!')
    24         session['name'] = form.name.data
    25         form.name.data = ''
    26         return redirect(url_for('.index'))
    27     all_user = User.query.all()
    28     return render_template('index.html', form=form, name=session.get('name'), known=session.get('known', False),
    29                            current_time=datetime.utcnow(), user_list=all_user)

    在蓝本中编写视图函数主要有两点不同:第一,和前面错误处理程序一样,路由装饰器由蓝本提供;第二url_for函数的用法不同,url_for('.index')。

    表单对象也移到了蓝本中

    app/main/forms.py

    from flask_wtf import FlaskForm
    from wtforms import StringField, SubmitField
    from wtforms.validators import DataRequired
    
    
    class NameForm(FlaskForm):
        name = StringField('What is your name?', validators=[DataRequired()])
        submit = SubmitField('Submit')

    7.4 启动脚本

    顶级文件夹中的manage.py用于启动程序。

    manage.py

     1 import os
     2 from app import create_app, db
     3 from app.models import User, Role
     4 from flask_script import Manager, Shell
     5 from flask_migrate import Migrate, MigrateCommand
     6 
     7 app = create_app(os.getenv('FLASK_CONFIG') or 'default')
     8 manager = Manager(app)
     9 migrate = Migrate(app, db)
    10 
    11 
    12 def make_shell_context():
    13     return dict(app=app, db=db, User=User, Role=Role)
    14 
    15 
    16 manager.add_command("shell", Shell(make_shell_context))
    17 manager.add_command("db", MigrateCommand)
    18 
    19 if __name__ == '__main__':
    20     manager.run()

    这个脚本先创建程序,如果已经定义了环境变量FLASK_CONFIG,则从变量中读取,否则使用'default'配置。

    7.5 需求文件

    程序中必须包含一个requirements.txt文件,用于记录程序所依赖的包和包的版本号,pip可以使用如下命令生产这个文件:

    (venv) pip freeze > requirements.txt

    如果要在新机器上传创建这个一样的虚拟环境,可运行以下命令。

    (venv)pip install -r requirements.txt

    alembic==0.9.9
    blinker==1.4
    click==6.7
    dominate==2.3.1
    Flask==0.12.2
    Flask-Bootstrap==3.3.7.1
    Flask-Mail==0.9.1
    Flask-Migrate==2.1.1
    Flask-Moment==0.6.0
    Flask-Script==2.0.6
    Flask-SQLAlchemy==2.3.2
    Flask-WTF==0.14.2
    itsdangerous==0.24
    Jinja2==2.10
    Mako==1.0.7
    MarkupSafe==1.0
    python-dateutil==2.7.2
    python-editor==1.0.3
    six==1.11.0
    SQLAlchemy==1.2.7
    visitor==0.1.3
    Werkzeug==0.14.1
    WTForms==2.1
  • 相关阅读:
    SSH防止超时的设置
    vuejs中v-bind绑定class时的注意事项
    js常用到的方法积累
    主流浏览器以及系统的判断
    理解Javascript的状态容器Redux
    可伸缩架构简短系列
    在Node.js中使用RabbitMQ系列一 Hello world
    在Node.js中使用RabbitMQ系列二 任务队列
    Javascript中的async await
    公钥,私钥和数字签名
  • 原文地址:https://www.cnblogs.com/LouisZJ/p/8932392.html
Copyright © 2011-2022 走看看