How do I use url_for if my method has multiple route annotations?

jiggy picture jiggy · Oct 16, 2011 · Viewed 15.2k times · Source

So I have a method that is accessible by multiple routes:

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

Now, how can I call url_for("foo") and know that I will get the first route?

Answer

Nemoden picture Nemoden · Oct 17, 2011

Ok. It took some delving into the werkzeug.routing and flask.helpers.url_for code, but I've figured out. You just change the endpoint for the route (in other words, you name your route)

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

will produce

canonical path is /canonical/path/, alternative is /alternate/path/

There is a drawback of this approach. Flask always binds the last defined route to the endpoint defined implicitly (foo in your code). Guess what happens if you redefine the endpoint? All your url_for('old_endpoint') will throw werkzeug.routing.BuildError. So, I guess the right solution for the whole issue is defining canonical path the last and name alternative:

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