python - Flask 应用程序工厂模式与 Flask-Mail

标签 python flask flask-mail

我有一个关于 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对象,我看到它没有设置配置变量。

Per this tutorial ,看来我需要手动设置 current_app.config['MAIL_DEFAULT_SENDER']每当使用mail时在此模式下的对象,需要额外编写 with app.app_context(): block 周围mail对象,以便使用正确的配置变量实例化它。

这看起来需要很多额外的工作,那么有没有其他方法可以直接获取 mailcreate_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)

最佳答案

这是一个导入问题。请阅读official documentation about Application Factories & Extensions .

说明:

  1. __init__.py 被加载,然后 mail 对象被创建。

  2. 在某个地方,调用create_app,然后创建一个新的app对象并使用之前创建的mail对象。

  3. 在处理create_app时,会导入蓝图。 (为什么需要在 app_context 中加载蓝图?)

  4. 导入蓝图时,它会从应用程序[...]、邮件导入。模块之间不共享导入(在这种情况下是肯定的)。因此,__init__.py 在导入时会再次执行,并创建一个未配置的新 mail 对象。 (如果您使用调试器,您将看到有 2 个邮件对象。)

最后,您有 2 个邮件对象:一个已配置,一个未配置

如何处理:

如文档中所述:

It’s preferable to create your extensions and app factories so that the extension object does not initially get bound to the application.

他们给出了以下示例:

You should not do:

def create_app(config_filename):
    app = Flask(__name__)
    app.config.from_pyfile(config_filename)

    db = SQLAlchemy(app)

But, rather, in model.py (or equivalent):

db = SQLAlchemy()

and in your application.py (or equivalent):

def create_app(config_filename):
   app = Flask(__name__)
   app.config.from_pyfile(config_filename)

   from yourapplication.model import db
   db.init_app(app)

最后,您应该在不同的文件中创建您的mail对象并将其导入您的__init__.py。如果您在此蓝图中仅使用mail对象,则可以直接在此蓝图中声明它。

您可以找到完整的example: Flaskr (Official example)就像使用 Flask-Mail 一样使用数据库扩展。

为什么这么困惑?您可以在 Google 上找到的大多数示例都不使用应用程序工厂,并且始终位于一个文件中。在他们的情况下,您将在同一个文件中声明所有内容。在您的情况下,您将在模块之间共享对象,因此它们应该可以正确访问。

关于python - Flask 应用程序工厂模式与 Flask-Mail,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62241636/

相关文章:

testing - 为什么 Flask-Mail 在测试期间实际上发送消息

docker - 尝试使用 Flask-mail 发送电子邮件时出现 SSL 错误

python - 使用 python pandas 或任何其他更好的库在工作表中添加一列并在整列中应用此 excel 公式

python - "word for word"语法在 Python 中意味着什么?

python - Flask sqlalchemy - 仅使用实体 ID 插入多对多

python - Flask 测试带有自定义 header 的放置请求

python - 为子域设置 SERVER_NAME 后 flask 中 www 前缀的问题

python - 按给定索引处的项目对列表进行排序

python - 是否可以使用 Python 元类反向继承?

python - Flask-Security邮件确认(Flask-Mail)不修改flask_security/utils.py发送失败