使用中间件在 Flask 请求中设置变量以在模板中使用

Setting a variable inside Flask request using Middleware to be used inside templates

根据访问应用程序的路径的第一部分,我希望应用程序以不同方式呈现。我尝试使用中间件在 request 上设置一个变量,然后在模板中访问它。我打印了一些调试信息,这些信息确实出现了,所以我知道中间件代码 运行,但是一旦我到达模板就没有设置值。如何在 Flask 中使用的中间件中设置变量?

from werkzeug.wrappers import Request

class NavMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        request = Request(environ)
        print('path: %s, url: %s' % (request.path, request.url))
        
        if request.path.startswith("/myapp"):
            print("Here")
            request.application = "Myapp"
            environ['application'] = "Myapp"
        
        return self.app(environ, start_response)
{% if request.application == "Myapp" %}
    {% include 'navbar_myapp.html' %}
{% endif %}

您在中间件中创建的 request 对象与 Flask 构建的 request 对象没有关系。只有 environ 在 WSGI 层之间传递。中间件修改后续层看到的请求的正确方法是修改 environ dict。您已完成该操作,因此您需要访问 request.environ 中的值,而不是 request 对象本身的值。

class NavMiddleware:
    def __init__(self, app, app_name):
        self.app = app
        self.app_name = app_name

    def __call__(self, environ, start_response):
        request = Request(environ)
        first_path = request.path.lstrip("/").partition("/")[0]
        environ["nav_middleware.app_name"] = first_path
        return self.app(environ, start_response)

app = Flask(__name__)
app.wsgi_app = NavMiddleware(app.wsgi_app, "my_app")
{% if request.environ["nav_middleware.app_name"] == "my_app" %}

这个答案一般适用于中间件,但在这种特殊情况下不需要中间件。 WSGI 服务器可以在不同的 SCRIPT_NAME 位置挂载应用程序,暴露为 request.script_root。您可以使用 Werkzeug 的 DispatcherMiddleware.

在 dev 中对此进行模拟
app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(app, {"/one": app, "/two": app})
{% if request.script_root == "/one" %}