带有Flask-Mail的Flask应用程序工厂模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有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对象后,我看到它没有设置任何配置变量。

Per this tutorial,似乎每次使用此模式下的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)
答案

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

说明:

  1. __init__.py已加载,然后创建了[[mail对象。

  2. 某个地方,调用

    create_app

  3. ,然后创建一个新的app对象,并使用先前创建的mail对象。
  4. 在处理

    create_app

  5. 时,会导入蓝图。 (为什么需要在app_context中加载蓝图?]
  6. 导入蓝图时,它导入from app [...], mail。导入不会在模块之间共享(在这种情况下是肯定的)。因此,在导入__init__.py并再次创建未配置的新

    mail

  7. 对象时,将再次执行。 (如果使用调试器,您将看到有两个邮件对象。)
最后,您有2个

mail

对象:一个已配置,一个未配置。

如何处理:

如文档中所述:

最好创建扩展程序和应用程序工厂,以使扩展程序对象最初不会绑定到应用程序。

他们给出以下示例:

您不应该这样做:

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)

最后,您应该在另一个文件中创建

mail

对象,然后将其导入您的__init__.py。如果仅在此蓝图中使用mail对象,则可以直接在此蓝图中声明它。
您可以在使用Flask-Mail时找到使用数据库扩展名的完整example: Flaskr (Official example)

为什么这么令人困惑?

] >>您可以在Google上找到的大多数示例,都不使用应用程序工厂,并且总是放在一个文件中。在这种情况下,您将在同一文件中声明所有内容。就您而言,您将在模块之间共享对象,因此应该可以正确访问它们。

以上是关于带有Flask-Mail的Flask应用程序工厂模式的主要内容,如果未能解决你的问题,请参考以下文章

发送消息时禁用登录 Flask-Mail

Flask扩展 -- flask-mail

flask-mail的使用

使用flask-mail扩展发送邮件

Flask-Mail 队列消息被发送到不同的电子邮件

Flask-Mail 尝试连接到 Gmail 时超时