【问题标题】:How do I use url_for if my method has multiple route annotations?如果我的方法有多个路由注释,我该如何使用 url_for?
【发布时间】:2011-12-08 14:00:42
【问题描述】:

所以我有一个可以通过多条路线访问的方法:

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

现在,我如何拨打url_for("foo") 并知道我会得到第一条路线?

【问题讨论】:

    标签: python google-app-engine flask werkzeug


    【解决方案1】:

    好的。对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。所以,我想整个问题的正确解决方案是定义规范路径最后一个和 name 替代:

    """ 
       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"))
    

    【讨论】:

    • 多么彻底而可爱的答案。给我一个验证的机会,我会将其标记为已接受。您也许应该将此提交给 pocoo 人员,以便正式记录。
    • 好的,在我升级到烧瓶 0.8 之前遇到了一些问题(0.7.2 失败)。它似乎也拿起了第一个注释,而不是我的最后一个。无论哪种方式,端点参数都是关键。
    【解决方案2】:

    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 生成都是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)

    【讨论】:

    • 在文档中有这个会很好(或者它已经存在?找不到)。你的最后一个例子正是我所需要的。
    【解决方案3】:

    此外,对于那些使用由变量构建的全部路由的用户:如果向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>
    

    当您点击“点击此处”链接时,您将被引导至“发布/创建”路线。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多