美文网首页
Flask Web 开发 【 Chapter 7 】大型程序结构

Flask Web 开发 【 Chapter 7 】大型程序结构

作者: 蜘蛛的梦呓 | 来源:发表于2018-05-10 19:17 被阅读0次

    【 Chapter 7 】大型结构目录

    7.1 项目结构

    Flask 程序基本的结构:

    #多文件 Flask 程序的基本结构
    
    |-flasky                                
      |-app/                            # Flask 程序一般保存在 app 的包中;
        |-templates/
        |-static/
        |-main/
          |-__init__.py
          |-errors.py
          |-forms.py
          |-views.py
        |-__init__.py
        |-email.py
        |-models.py
      |-migrations                          # migrations 文件夹包含数据库迁移脚本;
      |-tests/                              # tests 包中包含单元测试;
        |-__init__.py
        |-test*.py
      |venv/                                # 包含 Python 虚拟环境;
      |-requirements.txt                     # requirements.txt 列出所有的依赖包,便于在其他电脑上生成相同的                                       虚拟环境设置;
      |-config.py                            # config.py 存储配置;
      |-manage.py                            # manage.py 用于启动程序以及其他的程序任务;
    

    下面讲解把 hello.py 配置成如上的结构的过程。

    7.2 配置选项

    配置 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'
        MAIL_SERVER = os.environ.get('MAIL_SERVER', 'ssmtp.qq.com')
        MAIL_PORT = int(os.environ.get('MAIL_PORT', '465'))
        MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL', 'true').lower() in \
                       ['true', 'on', '1']
        # 发送者邮箱
        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')
        # 每次请求提交后,自动提交数据库的修改
        SQLALCHEMY_TRACK_MODIFICATIONS = False
    
        # 配置类可以定义 init_app() 类方法,其参数是程序实例。在这个方法中,可以执行对当前环境的配置初始化。
        @staticmethod
        def init_app(app):
            pass
    
    #开发配置类
    class DevelopmentConfig(Config):
        #调试阶段标记
        DEBUG = True
        # 初始化以及配置一个简单的 SQLlite 数据库
        # 设置 SQLite 数据库 URI
        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://'
    
    #产品配置类
    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 中包含通用配置,子类分别定义专用的配置。
    • 为了让配置方式更灵活且更安全,某些配置可以从环境变量中导入。如: SECRET_KEY
    • 在 3 个子类中,「 SQLALCHEMY_DATABASE_URI 」 变量都被指定了不同的值。这样程序就可在不同的配置环境中运行,每个环境都使用不同的数据库。
    • 配置类可以定义 init_app() 类方法,其参数是程序实例。在这个方法中,可以执行对当前环境的配置初始化。现在,基类 Config 中的 init_app() 方法为空。

    7.3 解析程序包

    程序包用来保存程序的所有代码、模板和静态文件。我们可以把这个包直接称为 app(应 用),如果有需求,也可使用一个程序专用名字。

    文件目录结构展示

    models.py: 程序中的数据库模型

    from . import db
    
    
    class Role(db.Model):
        __tablename__ = 'roles'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(64), unique=True)
        users = db.relationship('User', backref='role', lazy='dynamic')
    
        def __repr__(self):
            return '<Role %r>' % self.name
    
    
    class User(db.Model):
        __tablename__ = 'users'
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(64), unique=True, index=True)
        role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    
        def __repr__(self):
            return '<User %r>' % self.username
    

    email.py :程序汇总的电子邮件支持

    from threading import Thread
    from flask import current_app, render_template
    from flask_mail import Message
    from . import mail
    
    
    def send_async_email(app, msg):
        with app.app_context():
            mail.send(msg)
    
    
    def send_email(to, subject, template, **kwargs):
        app = current_app._get_current_object()
        msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                      sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
        msg.body = render_template(template + '.txt', **kwargs)
        msg.html = render_template(template + '.html', **kwargs)
        thr = Thread(target=send_async_email, args=[app, msg])
        thr.start()
        return thr
    

    ./app/init.py :创建不同配置的 app 的工厂函数

    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
    
    
    

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

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

    ./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 : 路由、视图函数函数

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

    tempalates 文件夹 :包含程序中的 Jinja2 模板文件

    static 文件夹 :包含程序中的静态文件

    ./tests/test_basics.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
    
    

    ./manage.py : 启动脚本

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

    ./requirements.txt : 记录索引的依赖包及版本号

    pip freeze > requirements.txt 生成赖文件
    pip install -r requirements.txt 生成新的虚拟环境
    

    其实也就是把 hello.py 各个功能的方法分成不同的 python 文件,再把其它的板块分门别类的放好,最后创建 manage.py 文件用来启动这个项目。

    相关文章

      网友评论

          本文标题:Flask Web 开发 【 Chapter 7 】大型程序结构

          本文链接:https://www.haomeiwen.com/subject/gertdftx.html