系統環境: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'))
