こんにちは、かつコーチです。
前回、最小構成のFlaskアプリを動かしましたが、実際のWebアプリには複数のページやURLが必要です。
この記事では、Flaskの心臓部とも言える@app.routeの使い方を、パターン別に整理して解説します。
ルーティングとは?
URLと処理を結びつける仕組み
ルーティングとは、「どのURLにアクセスされたら、どの処理を実行するか」を決める仕組みのことです。
Flaskでは@app.routeというデコレータ(関数に機能を追加する目印のような書き方)を使って、URLと関数を紐付けます。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "トップページ"
@app.route("/about")
def about():
return "会社概要ページ"
if __name__ == "__main__":
app.run(debug=True)
このコードでは、/にアクセスするとindex関数が、/aboutにアクセスするとabout関数が呼ばれます。
なぜルーティングの理解が重要なのか
Webアプリは基本的に「URLごとに違う画面や機能を提供するもの」です。
ルーティングの書き方を理解していないと、ページが増えるたびにコードがどう動いているか分からなくなってしまいます。
逆に言えば、ルーティングさえ押さえれば、Flaskアプリの構造の半分は理解できたと言っても過言ではありません。
基本の書き方・実装手順
手順1: 複数HTTPメソッドに対応する
WebのリクエストにはGET(データを取得する)やPOST(データを送信する)などのHTTPメソッド(通信の種類)があります。
methods引数を指定することで、対応するメソッドを制御できます。
from flask import Flask, request
app = Flask(__name__)
@app.route("/contact", methods=["GET", "POST"])
def contact():
if request.method == "POST":
name = request.form.get("name")
return f"{name}さん、送信ありがとうございます"
return "お問い合わせフォームです"
methodsを指定しない場合、デフォルトではGETのみ受け付けます。
フォーム送信を扱う場合は、必ずPOSTを明記する必要があります。
手順2: 動的なURLパラメータを受け取る
URLの一部を変数として受け取りたい場合は、<変数名>という記法を使います。
@app.route("/users/<username>")
def show_user(username):
return f"{username}さんのページです"
@app.route("/posts/<int:post_id>")
def show_post(post_id):
return f"{post_id}番目の投稿です(型: {type(post_id).__name__})"
<int:post_id>のように型を指定すると、Flask側で自動的に整数に変換してくれます。
型を指定しない場合は文字列として扱われるので、数値計算をしたい場合はintやfloatを明示しましょう。
手順3: リダイレクトとurl_forの活用
ページ移動を扱う際は、URLを直接文字列で書かず、url_for関数を使うのが定石です。
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route("/old-page")
def old_page():
return redirect(url_for("new_page"))
@app.route("/new-page")
def new_page():
return "新しいページです"
url_for("new_page")は、関数名から対応するURLを自動生成してくれます。
URLの構造を後から変更する際、url_forを使っていれば関数名さえ変わらなければコード修正が不要になります。
つまずきやすい設定・注意点
末尾スラッシュの有無で挙動が変わる
Flaskは、ルート定義の末尾に/を付けるかどうかで挙動が異なります。
@app.route("/users/")
def users():
return "ユーザー一覧"
このように末尾に/を付けた場合、/users(スラッシュなし)でアクセスすると自動的に/users/にリダイレクトされます。
逆に/users(スラッシュなし)で定義した場合、/users/(スラッシュあり)でアクセスすると404 Not Foundになります。
この違いを知らずに設計すると、後からURLの一貫性が崩れやすいので、プロジェクトの最初にルール(末尾スラッシュを付けるか統一する)を決めておくのがおすすめです。
よくあるつまずきポイント・エラー対処
同じ関数名を複数のルートで使ってエラーになる
❌ Before:異なるルートに同じ関数名を付けてしまい、アプリ起動時にAssertionError: View function mapping is overwriting an existing endpoint functionが出る
@app.route("/users")
def page():
return "ユーザー一覧"
@app.route("/posts")
def page(): # 関数名が重複している
return "投稿一覧"
✅ After:ルートごとに一意な関数名を付ける
@app.route("/users")
def user_list():
return "ユーザー一覧"
@app.route("/posts")
def post_list():
return "投稿一覧"
私自身、コピペでルートを増やしていったときにこのエラーに遭遇しました。
Flaskの関数名は単なる名前ではなく、url_forで参照する際のエンドポイント名(ルートを一意に識別するための名前)としても使われるため、重複が許されない仕様になっています。
int:を忘れて文字列比較になってしまう
❌ Before:<post_id>と型を指定せずに定義し、if post_id == 1:のような数値比較を書いてもFalseになってしまう(実際には文字列の”1″が渡ってくるため)
✅ After:<int:post_id>と型を指定して、Flask側で自動的に整数型に変換させる
型変換のミスは、エラーメッセージが出ずに「なぜか条件分岐が期待通りに動かない」という気づきにくいバグにつながるので要注意です。
応用・一歩先の使い方
Blueprintでルートを機能ごとに分割する
ルートの数が増えてくると、1つのapp.pyにすべて書くのは管理が大変になります。
FlaskにはBlueprintという、ルートを機能単位でファイル分割できる仕組みがあります。
from flask import Blueprint
user_bp = Blueprint("user", __name__)
@user_bp.route("/users")
def user_list():
return "ユーザー一覧"
app.py側でapp.register_blueprint(user_bp)と登録することで、機能ごとにファイルを分けたまま1つのアプリとして動作させられます。
中規模以上のアプリを作る際に必須のテクニックなので、ルーティングに慣れてきたら挑戦してみてください。
まとめ
この記事のポイント
@app.routeはURLと処理を結びつけるFlaskの基本機能methods引数でGET/POSTなどのHTTPメソッドを指定する<int:xxx>のように型を指定して動的なURLパラメータを受け取れるurl_forを使うことでURL変更に強いコードになる- 関数名の重複はエラーの原因になるため一意な名前を付ける
次に読むべき記事
ルーティングの基本が分かったら、次は画面表示を担当する「Jinja2テンプレートでHTMLを動的に生成する」に進みましょう。
文字列を直接returnするのではなく、本格的なHTML画面を作れるようになります。
タグ: Flask, 初心者向け, フレームワーク基礎