【簡說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'))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM