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
  • 相关阅读:
    The Python Standard Library
    Python 中的round函数
    Python文件类型
    Python中import的用法
    Python Symbols 各种符号
    python 一行写多个语句
    免费SSL证书(https网站)申请,便宜SSL https证书申请
    元宇宙游戏Axie龙头axs分析
    OLE DB provider "SQLNCLI10" for linked server "x.x.x.x" returned message "No transaction is active.".
    The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "xxx.xxx.xxx.xxx" was unable to begin a distributed transaction.
  • 原文地址:https://www.cnblogs.com/LouisZJ/p/8932392.html
Copyright © 2011-2022 走看看