Skip to main content
 首页 » 编程设计

python之Flask之不能使用来自其他文件的 Flask 和 Flask-mail 实例

2025年05月04日23落叶

我目前正在使用 Flask 构建一个应用程序。我正在努力访问 Flask 实例“app”以及 Flask-mail 实例“mail”。

下面是我的项目的样子:

└── my-project 
    ├── application 
    │   ├── __init__.py 
    │   ├── admin 
    │   │   ├── __init__.py 
    │   │   ├── forms.py 
    │   │   └── views.py 
    │   ├── auth 
    │   │   ├── __init__.py 
    │   │   ├── forms.py 
    │   │   └── views.py 
    │   │   └── token.py 
    │   │   └── email.py 
    │   ├── home 
    │   │   ├── __init__.py 
    │   │   └── views.py 
    │   ├── models.py 
    │   ├── static 
    │   └── templates 
    │       └──.... 
    │ 
    ├── config.py 
    ├── instance 
    │   └── config.py 
    ├── migrations 
    │   ├── README 
    │   ├── alembic.ini 
    │   ├── env.py 
    │   ├── script.py.mako 
    │   └── versions 
    │       └── a1a1d8b30202_.py 
    ├── requirements.txt 
    └── run.py 

Flask 实例是在 run.py 中使用 create_app 函数创建的(来自

运行.py

import os 
 
from application import create_app 
 
config_name = os.getenv('FLASK_CONFIG') 
app = create_app(config_name) 
 
if __name__ == '__main__': 
    app.run() 

应用程序/__init__.py

# third-party imports 
from flask import Flask, render_template 
from flask_sqlalchemy import SQLAlchemy 
from flask_login import LoginManager 
from flask_migrate import Migrate 
from flask_bootstrap import Bootstrap 
from flask_mail import Mail 
import stripe 
 
 
# local imports 
from config import app_config 
 
# db variable initialization 
db = SQLAlchemy() 
login_manager = LoginManager() 
LoginManager.user_loader 
 
def create_app(config_name): 
    app = Flask(__name__, instance_relative_config=True) 
    app.config.from_object(app_config[config_name]) 
    app.config.from_pyfile('config.py') 
 
 
    Bootstrap(app) 
    db.init_app(app) 
    login_manager.init_app(app) 
    mail = Mail(app) 
    migrate = Migrate(app,db) 
 
    from application import models 
 
    from .admin import admin as admin_blueprint 
    app.register_blueprint(admin_blueprint, url_prefix='/admin') 
    #the rest of the blueprint import goes here 
 
 
    return app 

我想做的是使用“应用程序”和“邮件”。例如,在 application/auth/token 中:

application/auth/token.py

from itsdangerous import URLSafeTimedSerializer 
 
from . import auth 
 
def generate_confirmation_token(email): 
    serializer = URLSafeTimedSerializer(app.config['SECRET_KEY']) 
    return serializer.dumps(email, salt=app.config['SECURITY_PASSWORD_SALT']) 
 
def confirm_token(token, expiration = 600): 
    serializer = URLSafeTimedSerializer(app.config['SECRET_KEY']) 
    try: 
        email = serializer.loads( 
            token, 
            salt=app.config['SECURITY_PASSWORD_SALT'], 
            max_age=expiration 
        ) 
    except: 
        return False 
    return email 

或在 application/auth/email.py 中:

application/auth/email.py

from flask_mail import Message 
 
from . import auth 
 
def send_mail(to, subject, template): 
    msg = Message( 
        subject, 
        recipients=[to], 
        html=template, 
        sender=app.config['MAIL_DEFAULT_SENDER'] 
    ) 
    mail.send(msg) 

我在 application/aut/views.py 中需要这两个函数

应用程序/auth/views.py

from flask import flash, redirect, render_template, url_for, request 
from flask_login import login_required, login_user, logout_user 
from werkzeug.security import check_password_hash 
import datetime 
 
from . import auth 
from forms import LoginForm, RegistrationForm 
from .. import db 
from ..models import User 
 
@auth.route('/register', methods=['GET', 'POST']) 
def register(): 
    """ 
    Handle requests to the /register route 
    Add a user to the database through the registration form 
    """ 
    form = RegistrationForm() 
    form.id = 'form_signup'  
    if form.validate_on_submit(): 
        user = User(email=form.email.data, 
                    #username=form.username.data, 
                    first_name=form.first_name.data, 
                    last_name=form.last_name.data, 
                    password=form.password.data, 
                    registered_on=datetime.datetime.now(), 
                    confirmed=False, 
                    premium=False) 
 
        # add employee to the database 
        db.session.add(user) 
        db.session.commit() 
        flash("We've just sent you an email confirmation. Please activate you account to completly finish your registration", 'succes') 
 
        token = generate_confirmation_token(user.email) 
        confirm_url = url_for('auth.confirm_email', token=token, _external=True) 
        html = render_template('auth/activate.html', confirm_url=confirm_url) 
        subject = "Please confirm your email" 
        send_email(user.email, subject, html) 
 
        login_user(user) 
 
        flash('A confirmation email has been sent via email.', 'success') 
 
        # redirect to the login page 
        #return redirect(url_for('auth.login')) 
        return redirect(url_for('home.homepage')) 
 
    # load registration template 
    return render_template('auth/register.html', form=form, title='Register') 
 
@auth.route('/confirm/<token>') 
@login_required 
def confirm_email(token): 
    try: 
        email = confirm_token(token) 
    except: 
        flash('The confirmation link is invalid or has expired.', 'danger') 
    user = User.query.filter_by(email=email).first_or_404() 
    if user.confirmed: 
        flash('Account already confirmed. Please login.', 'succes') 
    else: 
        user.confirmed =True 
        user.confirmed_on = datetime.datetime.now() 
        db.session.add(user) 
        db.session.commit() 
        flash("You've confirmed your account. Thanks!", 'succes') 
    return redirect(url_for('auth.login')) 

我得到的是错误“未定义全局名称应用程序”或“未定义全局名称邮件”。我尝试使用 from application import app 导入变量,它返回一个导入错误“无法导入应用程序”

感谢您的支持

请您参考如下方法:

由于您使用的是应用程序工厂,因此您需要使用 .init_app Flask-Mail 上的方法像你一样上课 Flask-SQLAlchemy类(class)。 from application import app将不起作用,因为在调用 create_app 之前,您永远不会初始化 flask 应用程序的实例。在 run.py 中发挥作用

应用程序/__init__.py

from flask_mail import Mail 
 
mail = Mail() 
 
 
def create_app(config_lvl): 
    # stuff 
 
    mail.init_app(app) 
    # more stuff 
    return app 

您也可以使用 current_app只要您使用它的代码块在 flask 应用程序中运行,就可以引用应用程序实例而不是实例本身。 Here是更深入的解释。

application/auth/email.py

from application import mail  # you can now import the Mail() object 
from flask_mail import Message 
from flask import current_app  # use this to reference current application context 
 
def send_email(to, subject, template): 
    msg = Message( 
        subject, 
        recipients=[to], 
        html=template, 
        sender=current_app.config['MAIL_DEFAULT_SENDER'] 
    ) 
    mail.send(msg) 

application/auth/token.py

from itsdangerous import URLSafeTimedSerializer 
from flask import current_app 
 
def generate_confirmation_token(email): 
    serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) 
    return serializer.dumps(email, salt=current_app.config['SECURITY_PASSWORD_SALT']) 
 
def confirm_token(token, expiration = 600): 
    serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) 
    try: 
        email = serializer.loads( 
            token, 
            salt=current_app.config['SECURITY_PASSWORD_SALT'], 
            max_age=expiration 
        ) 
    except: 
        return False 
    return email 

还应注意,您不需要 from . import auth在 auth 下的任何模块中除 views.py 外的蓝图

编辑

旁注:您不必将用户添加到 session 中,因为它是在您之前在路由中查询时添加的。我自己很长一段时间都没有意识到这一点。

@auth.route('/confirm/<token>') 
@login_required 
def confirm_email(token): 
    try: 
        email = confirm_token(token) 
    except: 
        flash('The confirmation link is invalid or has expired.', 'danger') 
    user = User.query.filter_by(email=email).first_or_404() 
    if user.confirmed: 
        flash('Account already confirmed. Please login.', 'success') 
    else: 
        user.confirmed = True 
        user.confirmed_on = datetime.datetime.now() 
      #  db.session.add(user) # can remove this 
        db.session.commit() 
        flash("You've confirmed your account. Thanks!", 'success') 
    return redirect(url_for('auth.login'))