zoukankan      html  css  js  c++  java
  • 【简说Python WEB】Flask应用的文件结构

    系统环境:Ubuntu 18.04.1 LTS

    Python使用的是虚拟环境:virutalenv

    Python的版本:Python 3.6.9

    【简说Python WEB】Flask应用的文件结构

    之前,我们应用了如下的组件:

    • flask-wtf
    • Flask-SQLAlchemy
    • Flask-Moment
    • Jinja2模板
    • Bootstrap
    • flask-mail
    • flask_migrate

    因为之前调试和应用组件,插件,导致app.py有一定的体量。对于大多数web应用来说,如果把代码都堆在以前,难以维护。而有一个不错的文件目录组织。可以很好的维护整个项目。通过自我学习,提炼出自己一套容易维护的文件结构。把之前的可以剥离出来的公用模块进行一个分离操作。

    1.文件结构的目录

    Zflask/
    ├── app
    │   ├── email.py
    │   ├── __init__.py
    │   ├── main
    │   │   ├── errors.py
    │   │   ├── forms.py
    │   │   ├── __init__.py
    │   │   └── views.py
    │   ├── models.py
    │   └── templates
    │       ├── 404.html
    │       ├── 500.html
    │       ├── base.html
    │       ├── index.html
    │       └── mail
    │           ├── new_user.html
    │           └── new_user.txt
    ├── config.py
    ├── LICENSE
    ├── README.md
    ├── requirements.txt
    └── zsdblog.py
    
    • app/email.py从原来app.py剥离出来的邮件功能

    • app/models.py把之前的users模型和roles模型,剥离出来.

    • app/__init__.py 一些初始化的通用脚本放在这里面,工厂函数
      
    • config.py配置文件

    • zsdblog.py主驱动应用,用于驱动整个项目

    • requirements.txt依赖包

    • main/errors.py剥离出来的自定义错误处理程序(剥离原来的程序)

    • main/forms.py表单处理程序(剥离原来的程序)

    • main/views.py自定义的应用路由程序(剥离原来的程序)

    • main/__init__.py 蓝本程序
      

    2.配置程序--config.py

    import os
    
    class Config:
        SQLALCHEMY_TRACK_MODIFICATIONS = False
    
        SECRET_KEY = 'wojiubugaosuni'
        MAIL_SERVER = 'smtp.qq.com'
        MAIL_PORT = 587
        MAIL_USE_TLS = True
        MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
        MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    
        ZSD_MAIL_SUBJECT_PREFIX = '[ZSD博客]'
        ZSD_MAIL_SENDER = 'ZSD博客 管理员 <543421410@qq.com>'
        ZSD_ADMIN = os.environ.get('ZSD_ADMIN')
    
        @staticmethod
        def init_app(app):
            pass
    
    class DevelopmentConfig(Config):
            DEBUG=True
            HOSTNAME = '172.30.200.252'
            DATABASE = 'zsd'
            USERNAME = 'zsd'
            PASSWORD = 'zsd'
            DB_URI = 'mysql+pymysql://{}:{}@{}:3306/{}?charset=utf8mb4'.format(
                     USERNAME, PASSWORD, HOSTNAME, DATABASE)
            SQLALCHEMY_DATABASE_URI = DB_URI
    
    class TestingConfig(Config):
            TESTING = True
    
    class ProductionConfig(Config):
        PROD = True        
    
    
    config = {
        'development': DevelopmentConfig,
        'testing': TestingConfig,
        'production': ProductionConfig,
    
        'default': DevelopmentConfig
    }
    

    把之前的URI驱动,MAIL配置,封装起来。通过不同的应用环境,调用不同的配置。

    3.app应用包

    数据库模型app/email.py和电子邮件函数程序app/models.py都移动至app包内。

    延迟构建应用实例,把创建过程移动到可以显示调用的工厂函数

    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
    

    整个代码中,可以看到引入了许多Flask的扩展。因为还没有初始化所需要的应用实例,这些构建类也没有真正的初始化,只是放在了那里。

    必须有一个应用,通过调用create_app函数,才算初始化了。

    4.剥离出来的email.py

    修改的代码如下:

    def send_email(to, subject, template, **kwargs):
        app = current_app._get_current_object()
        msg = Message(app.config['ZSD_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                      sender=app.config['ZSD_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 = current_app._get_current_object()调用的是current_app而不是原来的app

    5.蓝本(BLueprint)的应用

    蓝本(BLueprint)实现应用的模块化,可以定义路由和错误处理程序,使得应用层次更清晰。

    其中,蓝本中定义的路由和错误处理程序是处在sleep状态。只有蓝本注册到应用上面了,它们才成为应用的一部分。这种插槽式的应用构建,非常灵活。

    main/__init__.py 创建蓝本
    
    from flask import Blueprint
    
    main = Blueprint('main', __name__)
    
    from . import views, errors
    

    然后在app/init.py程序中,把蓝本在工厂函数create_app()中注册到应用上。

    app/__init__.py 蓝本注册
    #..
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    
    return app
    

    6.main目录的error.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
    

    其中errorhandler被换成了app_errorhandler, 相当于全局的错误处理程序。

    7. main目录的view.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)
                db.session.commit()
                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))
    

    其中current_app 替换了原来的app

                if current_app.config['FLASKY_ADMIN']:
                    send_email(current_app.config['FLASKY_ADMIN'], 'New User',
                               'mail/new_user', user=user)
    

    url_for('index')需要换成url_for('main.index')main代表这个蓝本下的index路由跳转。

    路由装饰器由蓝本提供,所以需要改成:@main.route

    8.主脚本

    zsdblog.py代码如下:

    import os
    from flask_migrate import Migrate
    from app import create_app, db
    from app.models import User, Role
    
    app = create_app(os.getenv('FLASK_CONFIG') or 'default')
    migrate = Migrate(app, db)
    
    
    @app.shell_context_processor
    def make_shell_context():
        return dict(db=db, User=User, Role=Role)
    

    上述脚本,创建一个应用实例,环境变量FLASK_CONFIG可以定义,如果不定义。做默认配置。

    这次,可以开启DEBUG模式,如下:

    设置环境变量:

    (zsdpy1) $ export FLASK_APP=zsdblog.py
    (zsdpy1) $ export FLASK_DEBUG=1
    

    9.需要安装的依赖包

    (zsdpy1) $ pip freeze >>requirements.txt
    

    10.应用启动

    (zsdpy1) $ flask run -h '0.0.0.0' -p 9000
    

    当然如果有db模型更新的话,可以使用

    flask db upgrade
    

    更新到最新的模型DDL语。

    应用效果如下:

    附录

    执行代码的时候,出现了如下错误 :

    werkzeug.routing.BuildError

    werkzeug.routing.BuildError: Could not build url for endpoint 'index'. Did you mean 'main.index' instead?

    File "/home/zsd/Zflask/app/main/views.py", line 24, in index

    return redirect(url_for('index'))
    

    可以看到/home/zsd/Zflask/app/main/views.py24行代码有问题,修改为如下 :

    return redirect(url_for('main.index'))
    
  • 相关阅读:
    day1-python简介+安装
    dgango中admin下添加搜索功能
    调用zabbix 分组api
    python 调用zabbix api实现查询主机信息,输出所有主机ip
    python实现用户登录界面
    怎样过滤跨站恶意脚本攻击(XSS)
    java服务安装(一):使用java service wrapper及maven打zip包
    详解Maven项目利用java service wrapper将Java程序生成Windows服务
    使用tomcat7-maven-plugin部署Web项目
    常用Maven插件介绍
  • 原文地址:https://www.cnblogs.com/zhangshengdong/p/12560353.html
Copyright © 2011-2022 走看看