如果我的方法有多个路由注释,如何使用url_for?

时间:2011-10-16 02:49:55

标签: python google-app-engine flask werkzeug

所以我有一个可以通过多种途径访问的方法:

@app.route("/canonical/path/")
@app.route("/alternate/path/")
def foo():
    return "hi!"

现在,我如何致电url_for("foo")并知道我将获得第一条路线?

3 个答案:

答案 0 :(得分:65)

确定。我花了一些时间来研究werkzeug.routingflask.helpers.url_for代码,但我已经想到了。您只需更改路线的endpoint(换句话说,命名您的路线)

@app.route("/canonical/path/", endpoint="foo-canonical")
@app.route("/alternate/path/")
def foo():
    return "hi!"

@app.route("/wheee")
def bar():
    return "canonical path is %s, alternative is %s" % (url_for("foo-canonical"), url_for("foo"))

将产生

  

规范路径是/ canonical / path /,替代是/ alternate / path /

这种方法有一个缺点。 Flask始终将最后定义的路由绑定到隐式定义的端点(代码中为foo)。猜猜如果重新定义端点会发生什么?您的所有url_for('old_endpoint')都会抛出werkzeug.routing.BuildError。所以,我想整个问题的正确解决方案是定义规范路径的最后一个和名称替代方案:

""" 
   since url_for('foo') will be used for canonical path
   we don't have other options rather then defining an endpoint for
   alternative path, so we can use it with url_for
"""
@app.route('/alternative/path', endpoint='foo-alternative')
""" 
   we dont wanna mess with the endpoint here - 
   we want url_for('foo') to be pointing to the canonical path
"""
@app.route('/canonical/path') 
def foo():
    pass

@app.route('/wheee')
def bar():
    return "canonical path is %s, alternative is %s" % (url_for("foo"), url_for("foo-alternative"))

答案 1 :(得分:51)

Flask中的规则是唯一的。如果你为同一个函数定义了绝对相同的URL,它默认会发生冲突,因为你正在做一些我们阻止你做的事情,因为从我们的角度来看是错误的。

有一个原因可能是您希望将多个URL连接到绝对相同的端点,并且这是与过去存在的规则的向后兼容性。从WZ0.8和Flask 0.8开始,您可以明确指定路径的别名:

@app.route('/')
@app.route('/index.html', alias=True)
def index():
    return ...

在这种情况下,如果用户请求/index.html,Flask将自动发出永久重定向至/

这并不意味着函数不能绑定到多个url,但在这种情况下你需要更改端点:

@app.route('/')
def index():
    ...

app.add_url_rule('/index.html', view_func=index, endpoint='alt_index')

或者:

@app.route('/')
@app.route('/index.html', endpoint='alt_index')
def index():
    ...

在这种情况下,您可以使用其他名称第二次定义视图。但是,这通常是您要避免的,因为然后视图函数必须检查request.endpoint以查看所调用的内容。相反,最好做这样的事情:

@app.route('/')
def index():
    return _index(alt=False)

@app.route('/index.html')
def alt_index():
    return _index(alt=True)

def _index(alt):
    ...

在这两种情况下,网址生成都是url_for('index')url_for('alt_index')

您也可以在路由系统级别执行此操作:

@app.route('/', defaults={'alt': False})
@app.route('/index.html', defaults={'alt': True})
def index(alt):
    ...

在这种情况下,网址生成为url_for('index', alt=True)url_for('index', alt=False)

答案 2 :(得分:0)

此外,对于使用catch的所有路径构造的变量:如果url_for传递包含变量的字典,Flask将正确创建url路径。

例如......

app.py:

app.route('/<path:pattern1>')
app.route('/<path:pattern1>/<path:pattern2>')
def catch_all(pattern1, pattern2=None):
    return render_template('template.html', p1=pattern1, p2=pattern2)

app.route('/test')
def test_routing:
    args = {'pattern1': 'Posts', 'pattern2': 'create'}
    return render_template('test.html', args=args)

的test.html:

<a href="{{url_for('catch_all', **args)}}">click here</a>

当您点击&#39;点击此处&#39;链接,您将被引导到&#39;帖子/创建&#39;路由。