【 Chapter 7 】大型結構目錄
7.1 項目結構
Flask 程序基本的結構:
#多文件 Flask 程序的基本結構
|-flasky
|-app/ # Flask 程序一般保存在 app 的包中;
|-templates/
|-static/
|-main/
|-__init__.py
|-errors.py
|-forms.py
|-views.py
|-__init__.py
|-email.py
|-models.py
|-migrations # migrations 文件夾包含數據庫遷移腳本;
|-tests/ # tests 包中包含單元測試;
|-__init__.py
|-test*.py
|venv/ # 包含 Python 虛擬環境;
|-requirements.txt # requirements.txt 列出所有的依賴包,便于在其他電腦上生成相同的 虛擬環境設置;
|-config.py # config.py 存儲配置;
|-manage.py # manage.py 用于啟動程序以及其他的程序任務;
下面講解把 hello.py 配置成如上的結構的過程。
7.2 配置選項
配置 config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
# 靈活、安全配置參數,并提供了默認值
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'
MAIL_SERVER = os.environ.get('MAIL_SERVER', 'ssmtp.qq.com')
MAIL_PORT = int(os.environ.get('MAIL_PORT', '465'))
MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL', 'true').lower() in \
['true', 'on', '1']
# 發送者郵箱
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
# 授權碼
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
# 郵件標題
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
# 發送者郵箱
FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'
# 管理員郵箱
FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')
# 每次請求提交后,自動提交數據庫的修改
SQLALCHEMY_TRACK_MODIFICATIONS = False
# 配置類可以定義 init_app() 類方法,其參數是程序實例。在這個方法中,可以執行對當前環境的配置初始化。
@staticmethod
def init_app(app):
pass
#開發配置類
class DevelopmentConfig(Config):
#調試階段標記
DEBUG = True
# 初始化以及配置一個簡單的 SQLlite 數據庫
# 設置 SQLite 數據庫 URI
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')
class TestingConfig(Config):
#測試階段標記
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
'sqlite://'
#產品配置類
class ProductionConfig(Config):
#產品數據庫
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'data.sqlite')
# 注冊了不同的配置環境,并注冊了一個默認配置
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
- 基類 Config 中包含通用配置,子類分別定義專用的配置。
- 為了讓配置方式更靈活且更安全,某些配置可以從環境變量中導入。如: SECRET_KEY
- 在 3 個子類中,「 SQLALCHEMY_DATABASE_URI 」 變量都被指定了不同的值。這樣程序就可在不同的配置環境中運行,每個環境都使用不同的數據庫。
- 配置類可以定義 init_app() 類方法,其參數是程序實例。在這個方法中,可以執行對當前環境的配置初始化。現在,基類 Config 中的 init_app() 方法為空。
7.3 解析程序包
程序包用來保存程序的所有代碼、模板和靜態文件。我們可以把這個包直接稱為 app(應 用),如果有需求,也可使用一個程序專用名字。
文件目錄結構展示
models.py: 程序中的數據庫模型
from . import db
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.relationship('User', backref='role', lazy='dynamic')
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return '<User %r>' % self.username
email.py :程序匯總的電子郵件支持
from threading import Thread
from flask import current_app, render_template
from flask_mail import Message
from . import mail
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(to, subject, template, **kwargs):
app = current_app._get_current_object()
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
sender=app.config['FLASKY_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/init.py :創建不同配置的 app 的工廠函數
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
./app/main/init.py : 創建藍本
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
./app/main/errors.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
./app.main/views.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)
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))
tempalates 文件夾 :包含程序中的 Jinja2 模板文件
static 文件夾 :包含程序中的靜態文件
./tests/test_basics.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
./manage.py : 啟動腳本
import os
from app import create_app,db
from app.models import User,Role
from flask_script import Manager,Shell
from flask_migrate import Migrate,MigrateCommand
app = create_app(os.getenv('Flask_CONFIG')or 'default')
manager = Manager(app)
migrate = Migrate(app,db)
def make_shell_context():
return dict(app=app,db=db,User=User,Role=Role)
manager.add_command("shell",Shell(make_context=make_shell_context()))
manager.add_command('db',MigrateCommand)
if __name__ == 'main':
manager.run()
./requirements.txt : 記錄索引的依賴包及版本號
pip freeze > requirements.txt 生成賴文件
pip install -r requirements.txt 生成新的虛擬環境
其實也就是把 hello.py 各個功能的方法分成不同的 python 文件,再把其它的板塊分門別類的放好,最后創建 manage.py 文件用來啟動這個項目。