如果我的方法有多个路由注释,如何使用url_for?
我有一个方法可以通过多个路径访问:
@app.route("/canonical/path/")
@app.route("/alternate/path/")
def foo():
return "hi!"
那么,我该怎么调用 url_for("foo")
,才能确保我得到的是第一个路径呢?
3 个回答
另外,对于那些使用变量构建的通用路由的用户来说:如果把一个包含变量的字典传给url_for
,Flask会正确生成网址路径。
举个例子...
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>
当你点击“点击这里”的链接时,你会被引导到“Posts/create”这个路由。
在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():
...
在这种情况下,你可以用不同的名称再次定义一个视图。然而,通常你会想要避免这样做,因为这样视图函数需要检查请求的端点来看看被调用的是哪个。更好的做法是这样:
@app.route('/')
def index():
return _index(alt=False)
@app.route('/index.html')
def alt_index():
return _index(alt=True)
def _index(alt):
...
在这两种情况下,生成URL的方式是 url_for('index')
或 url_for('alt_index')
。
你也可以在路由系统层面上这样做:
@app.route('/', defaults={'alt': False})
@app.route('/index.html', defaults={'alt': True})
def index(alt):
...
在这种情况下,生成URL的方式是 url_for('index', alt=True)
或 url_for('index', alt=False)
。
好的。我花了一些时间研究了 werkzeug.routing
和 flask.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 总是把最后定义的路由绑定到隐式定义的 endpoint(在你的代码中就是 foo
)。你猜如果重新定义 endpoint 会发生什么?所有的 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"))