url_for()
| 対応: | Flask 2(2021) |
|---|
『Flask』では、url_for() 関数を使ってエンドポイント名からURLを動的に生成します。URLをコードにハードコードするのではなく関数名を元に逆引きすることで、ルート定義を変更してもリンクやリダイレクト先を一括して追従させることができます。
構文
from flask import url_for
# 基本構文:エンドポイント名を文字列で渡してURLを取得します
url = url_for('エンドポイント名')
# 動的URLパラメータを渡す場合はキーワード引数で指定します
url = url_for('エンドポイント名', 変数名=値)
# クエリパラメータを付加したい場合もキーワード引数として渡します
# 動的パスに対応しない余分なキーワード引数は自動でクエリ文字列になります
url = url_for('エンドポイント名', page=2)
# _external=True でスキーム付きの絶対URLを生成します
url = url_for('エンドポイント名', _external=True)
引数一覧
| 引数 | 概要 |
|---|---|
| endpoint | URLを取得したいエンドポイント名を文字列で指定します。通常はビュー関数名と同じです。@app.route(endpoint='...') で明示的に設定した場合はその名前を使います。 |
| **values | 動的URLパラメータやクエリパラメータをキーワード引数で渡します。URLの <変数名> に対応するものはパスに埋め込まれ、残りはクエリ文字列として付加されます。 |
| _external | True を指定するとスキーム・ホスト名を含む絶対URLを返します。メール本文やAPIレスポンスなど、完全なURLが必要な場合に使います。デフォルトは False(相対パス)です。 |
| _scheme | _external=True と組み合わせて使うスキームを指定します(例: 'https')。省略時はリクエストのスキームを引き継ぎます。 |
| _anchor | URLの末尾に付加するフラグメント(アンカー)を指定します。例: _anchor='section1' → #section1 が付きます。 |
| _method | 特定のHTTPメソッド用のURLを生成したい場合に指定します。通常は不要ですが、同一パスに複数メソッドが紐づいている場合に使います。 |
サンプルコード
ユーザー管理アプリを例に、一覧・詳細・編集の各ページへのリンク生成と、フォーム送信後のリダイレクト、メール送信用の絶対URL生成を示します。
# ---- app.py ----
from flask import Flask, request, redirect, url_for, render_template
app = Flask(__name__)
# ダミーのユーザーデータです(実際はデータベースを使います)
users = [
{'id': 1, 'name': '山田 太郎', 'email': 'taro@example.com'},
{'id': 2, 'name': '鈴木 花子', 'email': 'hanako@example.com'},
]
# ユーザー一覧ページです
@app.route('/users/')
def user_list():
return render_template('user_list.html', users=users)
# ユーザー詳細ページです。URLから整数のIDを受け取ります
@app.route('/users/<int:user_id>/')
def user_detail(user_id):
user = next((u for u in users if u['id'] == user_id), None)
if user is None:
return 'ユーザーが見つかりません', 404
return render_template('user_detail.html', user=user)
# ユーザー編集ページです。GETとPOSTを同一ビューで処理します
@app.route('/users/<int:user_id>/edit/', methods=['GET', 'POST'])
def user_edit(user_id):
user = next((u for u in users if u['id'] == user_id), None)
if user is None:
return 'ユーザーが見つかりません', 404
if request.method == 'POST':
# フォームから送信された値で名前を更新します
user['name'] = request.form.get('name', user['name']).strip()
# 更新後は詳細ページへリダイレクトします(PRGパターン)
# url_for() でエンドポイント名 'user_detail' とパラメータからURLを生成します
# → /users/1/ のようなURLが返ります
return redirect(url_for('user_detail', user_id=user_id))
return render_template('user_edit.html', user=user)
# パスワードリセットのメール送信ビューです
@app.route('/users/<int:user_id>/reset-password/')
def send_reset_email(user_id):
user = next((u for u in users if u['id'] == user_id), None)
if user is None:
return 'ユーザーが見つかりません', 404
# メール本文に記載するURLは絶対URLが必要なため _external=True を指定します
# 例: https://example.com/users/1/reset-password/confirm/
reset_url = url_for('reset_password_confirm', user_id=user_id, _external=True)
# 実際のメール送信処理はここに書きます(今回は省略します)
print('リセットURL:', reset_url)
return 'パスワードリセットメールを送信しました。'
# パスワードリセット確認ページです(メール内リンクからアクセスされます)
@app.route('/users/<int:user_id>/reset-password/confirm/')
def reset_password_confirm(user_id):
return 'パスワードリセット確認ページです。'
if __name__ == '__main__':
app.run(debug=True)
<!-- templates/user_list.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ユーザー一覧</title>
</head>
<body>
<h1>ユーザー一覧</h1>
<ul>
{# users リストをループして各ユーザーの詳細ページへのリンクを生成します #}
{% for user in users %}
<li>
{#
url_for('user_detail', user_id=user.id) は
/users/1/ や /users/2/ のようなURLを返します。
ハードコードしないことでルート定義を変更してもリンクが自動追従します
#}
<a href="{{ url_for('user_detail', user_id=user.id) }}">
{{ user.name }}
</a>
</li>
{% endfor %}
</ul>
</body>
</html>
<!-- templates/user_detail.html -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>{{ user.name }}</title>
</head>
<body>
<h1>{{ user.name }}</h1>
<p>メール: {{ user.email }}</p>
{# 編集ページへのリンクです。user_id を引数として渡します #}
<a href="{{ url_for('user_edit', user_id=user.id) }}">編集する</a>
{#
クエリパラメータを付加する例です。
url_for('user_list', page=2) は /users/?page=2 を返します。
URLの動的パスに対応しないキーワード引数はクエリ文字列になります
#}
<a href="{{ url_for('user_list', page=2) }}">2ページ目へ</a>
{# 一覧ページへ戻るリンクです #}
<a href="{{ url_for('user_list') }}">一覧に戻る</a>
</body>
</html>
概要
url_for() はFlaskにおけるURL逆引き(リバースルックアップ)の関数です。URLをハードコードする代わりにエンドポイント名を使うことで、ルート定義のパスを後から変更してもテンプレートやリダイレクト先を一切修正せずに済みます。
引数のエンドポイント名は通常ビュー関数名と同じです。@app.route() に endpoint='名前' を明示した場合はその名前を使います。Blueprintを利用している場合は 'ブループリント名.ビュー関数名' の形式で指定します。
動的URLパラメータに対応するキーワード引数はパスに埋め込まれ、余分なキーワード引数はクエリ文字列として自動付加されます。_external=True を指定するとスキームとホスト名を含む絶対URLが返されるため、メール本文やAPIレスポンスで完全なURLが必要な場合に使います。
テンプレート内でも同名の url_for() がJinja2のグローバル関数として使用でき、Python側と同じ記法でURLを生成できます。ルーティングの定義については @app.route() をご参照ください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。