sarbjit
sarbjit

Reputation: 3894

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

Based on the first part of the path an app is accessed from, I want the app to render differently. I tried setting a variable on the request using middleware and then accessing it in the template. I printed some debug information, which did show up so I know the middleware code ran, but the value wasn't set once I got to the template. How can I set a variable inside middleware that can be used in 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 %}

Upvotes: 5

Views: 2409

Answers (1)

davidism
davidism

Reputation: 127190

The request object you created in the middleware has no relation to the request object that Flask builds. Only the environ is passed between WSGI layers. The correct way for middleware to modify the request that subsequent layers see is to modify the environ dict. You've done that, so you need to access the value in request.environ, not on the request object itself.

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" %}

This answer applies to middleware in general, but in this particular case there's no need for middleware. WSGI servers can mount applications at different SCRIPT_NAME locations, which is exposed as request.script_root. You can simulate this in dev with Werkzeug's DispatcherMiddleware.

app = Flask(__name__)
app.wsgi_app = DispatcherMiddleware(app, {"/one": app, "/two": app})
{% if request.script_root == "/one" %}

Upvotes: 5

Related Questions