web-dev-qa-db-ja.com

メソッドに複数のルートアノテーションがある場合、url_forを使用するにはどうすればよいですか?

だから私は複数のルートでアクセスできるメソッドを持っています:

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

さて、どうすればurl_for("foo")を呼び出して、最初のルートを取得することができますか?

39
jiggy

OK。 _werkzeug.routing_と_flask.helpers.url_for_のコードを少し掘り下げましたが、私は理解しました。ルートのendpointを変更するだけです(つまり、あなたはnameあなたのルート)

_@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"))
_
65
Nemoden

Flask内のルールは一意です。同じ関数に絶対に同じURLを定義すると、デフォルトで競合します。なぜなら、私たちの見解では間違っているので、私たちがあなたにやらせないことをしているからです。 。

完全に同じエンドポイントに複数のURLを設定する理由は1つあります。これは、過去に存在したルールとの下位互換性があるためです。 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)です。

51
Armin Ronacher

さらに、変数で構成されたすべてのルートをキャッチを使用する場合:Flaskは、url_forには、変数を含む辞書が渡されます。

例えば...

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>

「ここをクリック」リンクをクリックすると、「投稿/作成」ルートに移動します。

0
vincent