NFicano NFicano - 6 months ago 29
Python Question

Flask hit decorator before before_request signal fires

I'm using Flask and using the before_request decorator to send information about
requests to an analytics system. I'm now trying to create a decorator that would
prevent sending these events on a few routes.

The problem I'm running into is getting my decorator to get called before the before_request
signal gets fired.

def exclude_from_analytics(func):

@wraps(func)
def wrapped(*args, **kwargs):
print "Before decorated function"
return func(*args, exclude_from_analytics=True, **kwargs)

return wrapped

# ------------------------

@exclude_from_analytics
@app.route('/')
def index():
return make_response('..')

# ------------------------

@app.before_request
def analytics_view(*args, **kwargs):
if 'exclude_from_analytics' in kwargs and kwargs['exclude_from_analytics'] is True:
return

Answer

You can use the decorator to simply put an attribute on the function (in my example below, I'm using _exclude_from_analytics as the attribute). I find the view function using a combination of request.endpoint and app.view_functions.

If the attribute is not found on the endpoint, you can ignore analytics.

from flask import Flask, request

app = Flask(__name__)

def exclude_from_analytics(func):
    func._exclude_from_analytics = True
    return func

@app.route('/a')
@exclude_from_analytics
def a():
    return 'a'

@app.route('/b')
def b():
    return 'b'

@app.before_request
def analytics_view(*args, **kwargs):
    # Default this to whatever you'd like.
    run_analytics = True

    # You can handle 404s differently here if you'd like.
    if request.endpoint in app.view_functions:
        view_func = app.view_functions[request.endpoint]
        run_analytics = not hasattr(view_func, '_exclude_from_analytics')

    print 'Should run analytics on {0}: {1}'.format(request.path, run_analytics)

app.run(debug=True)

The output (ignoring static files...)

Should run analytics on /a: False
127.0.0.1 - - [24/Oct/2013 15:55:15] "GET /a HTTP/1.1" 200 -
Should run analytics on /b: True
127.0.0.1 - - [24/Oct/2013 15:55:18] "GET /b HTTP/1.1" 200 -

I have not tested to see if this works with blueprints. Additionally, a decorator that wraps and returns a NEW function could cause this to not work since the attribute might be hidden.

Comments