1. 程式人生 > >【簡說Python WEB】Flask應用的檔案結構

【簡說Python WEB】Flask應用的檔案結構

目錄

  • 【簡說Python WEB】Flask應用的檔案結構
    • 1.檔案結構的目錄
    • 2.配置程式--config.py
    • 3.app應用包
    • 4.剝離出來的email.py
    • 5.藍本(BLueprint)的應用
    • 6.main目錄的error.py程式碼剝離:
    • 7. main目錄的view.py程式碼剝離:
    • 8.主指令碼
    • 9.需要安裝的依賴包
    • 10.應用啟動
    • 附錄

系統環境: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部落格 管理員 <[email protected]>'
    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'))