【簡說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.py
24行程式碼有問題,修改為如下 :
return redirect(url_for('main.index'))