python - 使用 Flask-Mail 的 Flask 应用程序工厂模式
问题描述
我有一个关于 Flask 应用程序工厂模式的简单概念问题。
我正在尝试在不同的文件中使用Flask-Mail 。我的__init__.py
文件是:
#
# __init__.py
#
from flask import Flask
from flask_pymongo import PyMongo
from flask_mail import Mail
from flask_login import LoginManager
mail = Mail()
mongo = PyMongo()
login_manager = LoginManager()
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.DevConfig')
mail.init_app(app)
login_manager.init_app(app)
mongo.init_app(app, retryWrites = False)
with app.app_context():
from .views import bp
app.register_blueprint(views.bp)
return app
另一个文件:
#
# views.py
#
from flask import Blueprint
from flask import current_app as app
from flask_mail import Message
from app import mongo, mail, login_manager
bp = Blueprint('bp', __name__, template_folder='templates', static_folder='static')
@bp.route('/')
def index():
msg = Message("Success", recipients=[ email ])
with open('template.html', 'r') as fd:
msg.html = fd.read()
mail.send(msg)
尽管我MAIL_DEFAULT_SENDER
在配置文件中进行了设置,但我收到错误消息,即mail.send(msg)
在views.py
. 检查mail
对象后,我看到它没有设置配置变量。
根据本教程,似乎我需要在此模式下current_app.config['MAIL_DEFAULT_SENDER']
使用mail
对象时手动设置,并且需要with app.app_context():
在对象周围编写一个附加块mail
,以便使用正确的配置变量对其进行实例化。
这似乎需要做很多额外的工作,那么有没有另一种方法可以直接获取mail
已初始化并create_app
设置了所有正确配置变量的对象?
感谢您的帮助!
编辑:
创建extensions.py
:
from flask_pymongo import PyMongo
from flask_mail import Mail
from flask_login import LoginManager
mail = Mail()
mongo = PyMongo()
login_manager = LoginManager()
并修改__init__.py
为:
from flask import Flask
def create_app():
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('config.DevConfig')
from app.extensions import mail, login_manager, mongo
mail.init_app(app)
login_manager.init_app(app)
mongo.init_app(app, retryWrites = False)
with app.app_context():
from .views import bp
app.register_blueprint(views.bp)
return app
对于views.py
,我有:
from flask import Blueprint
from flask import current_app
from flask_mail import Message
from app.extensions import mongo, mail, login_manager
bp = Blueprint('bp', __name__, template_folder='templates', static_folder='static')
@bp.route('/')
def index():
msg = Message("Success", recipients=[ email ])
with open('template.html', 'r') as fd:
msg.html = fd.read()
mail.send(msg)
解决方案
这是一个进口问题。请阅读有关 Application Factories & Extensions 的官方文档。
说明:
__init__.py
加载,然后创建邮件对象。在某处调用create_app ,然后创建一个新的应用程序对象并使用之前创建的邮件对象。
在处理create_app时,会导入蓝图。(为什么需要在app_context中加载蓝图?)
在导入蓝图时,它会导入
from app [...], mail
. 导入不会在模块之间共享(在这种情况下是肯定的)。所以__init__.py
在导入时再次执行,并创建了一个未配置的新邮件对象。(如果您使用调试器,您会看到有 2 个邮件对象。)
最后,您有 2 个邮件对象:一个已配置,一个未配置。
如何处理:
如文档中所述:
最好创建您的扩展和应用程序工厂,以便扩展对象最初不会绑定到应用程序。
他们给出了以下示例:
你不应该这样做:
def create_app(config_filename): app = Flask(__name__) app.config.from_pyfile(config_filename) db = SQLAlchemy(app)
但是,更确切地说,在 model.py (或等效)中:
db = SQLAlchemy()
并在您的 application.py (或等效)中:
def create_app(config_filename): app = Flask(__name__) app.config.from_pyfile(config_filename) from yourapplication.model import db db.init_app(app)
最后,您应该在不同的文件中创建您的邮件对象并将其导入您的__init__.py
. 如果您只使用本蓝图中的邮件对象,则可以直接在本蓝图中声明。
您可以找到一个完整的示例:Flaskr(官方示例),它在您使用 Flask-Mail 时使用 DB 扩展。
为什么会如此混乱?您可以在 Google 上找到的大多数示例不使用应用程序工厂,并且始终在一个文件中。在他们的情况下,您将在同一个文件中声明所有内容。在您的情况下,您将在模块之间共享对象,因此它们应该可以正确访问。
推荐阅读
- java - 通过 WebFlux 客户端获取不同的错误 DTO
- java - 在 Spark Java 中通过 Websocket 发送消息
- python - 有没有办法选择在二元粒子群优化中选择多少个特征?
- laravel - JwtAuth 没有在 Backpack Laravel 中生成令牌
- python - 如何使用最少的内存创建一个设定长度的迭代?
- c++ - C++ 以任意顺序读取输入
- reactjs - 如何在 react-trello 中创建自定义通道(列)?
- flutter - 如何在 Flutter 中为整个应用设置 letterSpacing?
- javascript - 提交表格后不显示
- tcp - 用于在 Linux 中计算 TCP 校验和的内联汇编代码