Skip to content Skip to sidebar Skip to footer

Flask: Why App.route() Decorator, Should Always Be The Outermost?

Say, I have a hand-crafted @login-required decorator: from functools import wraps def login_required(decorated_function): '''Decorator to check if user is logged in.'''

Solution 1:

You have almost explained it yourself! :-) app.route does

self.add_url_rule(rule, endpoint, f, **options)

But the key is that f here is whatever function was decorated. If you apply app.route first, it adds a URL rule for the original function (without the login decorator). The login decorator wraps the function, but app.route has already stored the original unwrapped version, so the wrapping has no effect.

It may help to envision "unrolling" the decorators. Imagine you did it like this:

# plain function
def index():
    return"Hello!"

login_wrapped = login_required(index)         # login decorator
both_wrapped = app.route('/')(login_wrapped)  # route decorator

This is the "right" way where the login wrap happens first and then the route. In this version, the function that app.route sees is already wrapped with the login wrapper. The wrong way is:

# plain function
def index():
    return"Hello!"

route_wrapped = app.route('/')(index)        # route decorator
both_wrapped = login_wrapped(route_wrapped)  # login decorator

Here you can see that what app.route sees is only the plain unwrapped version. The fact that the function is later wrapped with the login decorator has no effect, because by that time the route decorator has already finished.

Post a Comment for "Flask: Why App.route() Decorator, Should Always Be The Outermost?"