これを回避する 1 つの方法は、登録されたルールのmatch_compare_key()
メソッドを偽装して、ルールの並べ替えアルゴリズムをごまかすことです。このハックは、app.route()
(Flask オブジェクト) に直接登録されたルートでのみ機能し、ブループリントでは機能しないことに注意してください。ブループリントのルートは、ブループリントがメイン アプリに登録されたときにのみグローバル URL マップに追加されるため、生成されたルールを変更するのは困難です。
# an ordinary route
@app.route('/<var1>/<var2>/<var3>')
def some_view(var1, var2, var3):
pass
# let's find the rule that was just generated
rule = app.url_map._rules[-1]
# we create some comparison keys:
# increase probability that the rule will be near or at the top
top_compare_key = False, -100, [(-2, 0)]
# increase probability that the rule will be near or at the bottom
bottom_compare_key = True, 100, [(2, 0)]
# rig rule.match_compare_key() to return the spoofed compare_key
rule.match_compare_key = lambda: top_compare_key
この場合、結果のスプーフィングされた関数はルール オブジェクトにバインドされないことに注意してください。したがって、 を呼び出すと、関数は引数rule.match_compare_key()
を受け取りません。self
関数を適切にバインドする場合は、代わりに次のようにします。
spoof = lambda self: top_compare_key
rule.match_compare_key = spoof.__get__(rule, type(rule))
上記をデコレータで一般化できます
def weighted_route(*args, **kwargs):
def decorator(view_func):
compare_key = kwargs.pop('compare_key', None)
# register view_func with route
app.route(*args, **kwargs)(view_func)
if compare_key is not None:
rule = app.url_map._rules[-1]
rule.match_compare_key = lambda: compare_key
return view_func
return decorator
# can be used like @app.route(). To weight the rule, just provide
# the `compare_key` param.
@weighted_route('/<var1>/<var2>/<var3>', compare_key=bottom_compare_key)
def some_view(var1, var2, var3):
pass
コンテキストマネージャーとして実装された同じハック。
import contextlib
@contextlib.contextmanager
def weighted_route(compare_key=None):
yield
if compare_key is not None:
rule = app.url_map._rules[-1]
rule.match_compare_key = lambda: compare_key
# and to use
with weighted_route(compare_key):
@app.route('/<var1>/<var2>/<var3>')
def some_view(var1, var2, var3):
pass