Flask:如何在应用程序上下文之外使用 url_for()?

Hou*_*man 7 python flask

我正在编写一个脚本来收集那些没有收到电子邮件确认电子邮件的用户的电子邮件并将其重新发送给他们。该脚本显然在 Flask 应用程序上下文之外工作。我想使用 url_for() 但无法正确使用。

def resend(self, csv_path):
    self.ctx.push()
    with open(csv_path) as csv_file:
        csv_reader = csv.reader(csv_file)
        for row in csv_reader:
            email = row[0]
            url_token = AccountAdmin.generate_confirmation_token(email)
            confirm_url = url_for('confirm_email', token=url_token, _external=True)
        ...
    self.ctx.pop()
Run Code Online (Sandbox Code Playgroud)

我要做的第一件事是在配置中设置 SERVER_NAME。但后来我收到此错误消息:

werkzeug.routing.BuildError:无法使用值 ['token'] 为端点“confirm_email”构建 url。您的意思是“静态”吗?

这是它的定义方式,但我认为它甚至找不到这个,因为它在作为脚本运行时没有注册:

app.add_url_rule('/v5/confirm_email/<token>', view_func=ConfirmEmailV5.as_view('confirm_email'))
Run Code Online (Sandbox Code Playgroud)

有没有办法挽救 url_for() 还是我必须建立自己的网址?谢谢

Ben*_* Zu 3

从应用程序上下文中获取 URL 更加容易和正确。

您可以导入应用程序并使用app_context https://flask.palletsprojects.com/en/2.0.x/appcontext/#manually-push-a-context手动推送上下文

from flask import url_for
from whereyoudefineapp import application
application.config['SERVER_NAME'] = 'example.org'
with application.app_context():
    url_for('yourblueprint.yourpage')
Run Code Online (Sandbox Code Playgroud)

或者您可以重新定义您的应用程序并注册所需的蓝图。

from flask import Flask, url_for
from whereyoudefineyourblueprint import myblueprint
application = Flask(__name__)
application.config['SERVER_NAME'] = 'example.org'
application.register_blueprint(myblueprint)
with application.app_context():
    url_for('myblueprint.mypage')
Run Code Online (Sandbox Code Playgroud)

我们也可以想象不使用应用程序的不同方法来做到这一点,但我没有看到任何足够/正确的解决方案。

尽管如此,我仍然会建议这个肮脏的解决方案。

假设您有以下蓝图,其中包含以下路线routes.py

from flask import Blueprint

frontend = Blueprint('frontend', __name__)

@frontend.route('/mypage')
def mypage():
    return 'Hello'

@frontend.route('/some/other/page')
def someotherpage():
    return 'Hi'

@frontend.route('/wow/<a>')
def wow(a):
    return f'Hi {a}'
Run Code Online (Sandbox Code Playgroud)

您可以使用该库inspect获取源代码,然后解析它以构建 URL。

import inspect
import re

BASE_URL = "https://example.org"

class FailToGetUrlException(Exception):
    pass

def get_url(function, complete_url=True):
    source = inspect.getsource(function)
    lines = source.split("\n")

    for line in lines:
        r = re.match(r'^\@[a-zA-Z]+\.route\((["\'])([^\'"]+)\1', line)
        if r:
            if complete_url:
                return BASE_URL + r.group(2)
            else:
                return r.group(2)
    
    raise FailToGetUrlException


from routes import *
print(get_url(mypage))
print(get_url(someotherpage))
print(get_url(wow).replace('<a>', '456'))
Run Code Online (Sandbox Code Playgroud)

输出:

https://example.org/mypage
https://example.org/some/other/page
https://example.org/wow/456
Run Code Online (Sandbox Code Playgroud)