我正在练习烧瓶。我制作了一个简单的 Flask 应用程序,它向管理员发送一封电子邮件,说“新用户已加入”。一旦有人输入自己的名字并在表格上提交。
这是电子邮件组件:
from flask import current_app, render_template
from flask_mail import Message
from threading import Thread
from app import mail
# Send aync email functions
def send_aysnc_email(app, msg):
with app.app_context():
mail.send(msg)
def send_mail(to, subject, template, **kwargs):
app = current_app
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_aysnc_email, args=[app, msg])
thr.start()
return thr
当我运行应用程序并在表单上输入姓名并按提交时,电子邮件不会发送。
我在日志中收到一条错误消息
Exception in thread Thread-3 (send_aysnc_email):
Traceback (most recent call last):
File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
127.0.0.1 - - [02/Sep/2023 14:39:29] "POST / HTTP/1.1" 302 -
self.run()
File "/usr/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/home/cadbay53/Desktop/practice/flask/app/emails.py", line 9, in send_aysnc_email
with app.app_context():
File "/home/cadbay53/Desktop/practice/flask/venv/lib/python3.10/site-packages/werkzeug/local.py", line 311, in __get__
obj = instance._get_current_object()
File "/home/cadbay53/Desktop/practice/flask/venv/lib/python3.10/site-packages/werkzeug/local.py", line 508, in _get_current_object
raise RuntimeError(unbound_message) from None
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that needed
the current application. To solve this, set up an application context
with app.app_context(). See the documentation for more information.
我找到了解决此问题的方法,但我不明白为什么当前代码不起作用。
这是我的应用程序工厂:
from flask import Flask, render_template
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
这是我创建应用程序实例的文件:
import os
from app import create_app
from app.models import User, Role
from flask_migrate import Migrate
from app import db
app = create_app("default")
migrate = Migrate(app, db)
@app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Role=Role)
@app.cli.command()
def test():
"""Run unit tests."""
import unittest
tests = unittest.TestLoader().discover("tests")
unittest.TextTestRunner(verbosity=2).run(tests)
这些是配置:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = "***"
MAIL_SERVER = "smtp.gmail.com"
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = "***@***.com"
MAIL_PASSWORD = "****"
FLASKY_MAIL_SUBJECT_PREFIX = "[Flasky]"
FLASKY_MAIL_SENDER = "Flasky Admin <***@***.com>"
FLASKY_ADMIN = "***@***.com"
SQLALCHEMY_TRACK_MODIFICATIONS = False
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "data-dev.sqlite")
class TestConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = "sqlite:///"
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "data.sqlite")
config = {
"development": DevelopmentConfig,
"testing": TestConfig,
"production": ProductionConfig,
"default": DevelopmentConfig,
}
这是我的工作:
# Send aync email functions
def send_aysnc_email(app, msg):
with app.app_context():
mail.send(msg)
def send_mail(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_aysnc_email, args=[app, msg])
thr.start()
return thr
我不明白为什么当提供当前应用程序作为参数并且与
app.app_context()
配合使用时,current_app._get_current_object()
无法访问当前应用程序实例。
current_app
是Flask提供的代理对象,动态解析为当前Flask应用上下文。
使用
current_app._get_current_object()
是一种有效的技术,可以在单独的线程中访问当前应用程序实例,而无需建立新的应用程序上下文。这种方法可以有效地检索应用程序实例,而不会破坏现有的应用程序上下文。