14

私は Flask を使用しており、 before_request デコレーターを使用して、リクエストに関する情報を分析システムに送信しています。私は現在、これらのイベントをいくつかのルートで送信しないようにするデコレータを作成しようとしています。

私が直面している問題は、before_request シグナルが発生する前にデコレータを呼び出させることです。

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
4

2 に答える 2

19

デコレータを使用して、単純に関数に属性を設定できます (以下の例では_exclude_from_analytics、属性として使用しています)。request.endpointapp.view_functionsの組み合わせを使用してビュー関数を見つけます。

エンドポイントで属性が見つからない場合は、分析を無視できます。

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)

出力 (静的ファイルは無視します...)

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 -

これが設計図で機能するかどうかはテストしていません。さらに、 NEW 関数をラップして返すデコレーターは、属性が隠されている可能性があるため、これが機能しない原因になる可能性があります。

于 2013-10-24T19:57:30.040 に答える
3

関数をラップして返す@Mark Hildreth の回答のバリエーションを次に示します。

from functools import wraps
from flask import Flask, request, g

app = Flask(__name__)

def exclude_from_analytics(*args, **kw):
    def wrapper(endpoint_method):
        endpoint_method._skip_analytics = True

        @wraps(endpoint_method)
        def wrapped(*endpoint_args, **endpoint_kw):
            # This is what I want I want to do. Will not work.
            #g.skip_analytics = getattr(endpoint_method, '_skip_analytics', False)
            return endpoint_method(*endpoint_args, **endpoint_kw)
        return wrapped
    return wrapper

@app.route('/')
def no_skip():
    return 'Skip analytics? %s' % (g.skip_analytics)

@app.route('/skip')
@exclude_from_analytics()
def skip():
    return 'Skip analytics? %s' % (g.skip_analytics)

@app.before_request
def analytics_view(*args, **kwargs):
    if request.endpoint in app.view_functions:
        view_func = app.view_functions[request.endpoint]
        g.skip_analytics = hasattr(view_func, '_skip_analytics')
        print 'Should skip analytics on {0}: {1}'.format(request.path, g.skip_analytics)

app.run(debug=True)

私が期待し期待したほど単純に機能しない理由は、Flask コンテキスト スタックとコールバックが適用される順序に関係しています。メソッド呼び出しのタイムラインを次に示します (削除されてからのいくつかのデバッグ ステートメントに基づく)。

$ python test-flask-app.py
# Application Launched
DECORATOR exclude_from_analytics
DECORATOR wrapper
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

# REQUEST: /
DECORATOR app.before_request: analytics_view
> Should skip analytics on /: False
ENDPOINT no_skip
127.0.0.1 - - [14/May/2016 16:10:39] "GET / HTTP/1.1" 200 -

# REQUEST: /skip
DECORATOR app.before_request: analytics_view
> Should skip analytics on /skip: True
DECORATOR wrapped
ENDPOINT skip
127.0.0.1 - - [14/May/2016 16:12:46] "GET /skip HTTP/1.1" 200 -

g.skip_analytics関数内から設定することをお勧めしwrappedます。しかし、それはフックの後まで呼び出されないため、Markanalytics_view @app.before_request例に従い、起動時にのみ呼び出されるアプリケーション( requestではなく) コンテキストを_skip_analytics呼び出しているエンドポイント メソッドに attrを設定する必要がありました。

flask.gアプリのコンテキストの詳細については、このStackOverflow answerを参照してください。

于 2016-05-14T23:39:43.940 に答える