解决此问题的一种方法是通过欺骗已注册规则的match_compare_key() 方法来欺骗规则排序算法。请注意,此 hack 仅适用于直接使用 app.route()(Flask 对象)注册的路由,不适用于蓝图。蓝图的路由只有在蓝图在主应用上注册后才会添加到全局 url Map,这使得修改生成的规则具有挑战性。
# 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
与上下文管理器相同的 hack。
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