request.args
| 対応: | Flask 2(2021) |
|---|
『Flask』では、request.args を使ってURLのクエリパラメータを取得します。クエリパラメータとはURLの ? 以降に続く キー=値 の形式のデータで、検索条件やページ番号など、GETリクエストで情報を渡す際によく使われます。request.args は辞書に似たオブジェクトで、キーを指定して値を取り出せます。
構文
from flask import Flask, request
app = Flask(__name__)
@app.route('/search/')
def search():
# .get() で取得します。キーが存在しない場合は None を返します
keyword = request.args.get('q')
# 第2引数でデフォルト値を指定できます
page = request.args.get('page', 1)
# [] でも取得できますが、キーがない場合は例外が発生します
# keyword = request.args['q']
# 同名キーが複数ある場合は .getlist() で全件リストで取得します
tags = request.args.getlist('tag')
主なメソッド・プロパティ一覧
| メソッド / プロパティ | 概要 |
|---|---|
request.args.get(key) | 指定したキーの値を文字列で返します。キーが存在しない場合は None を返します。 |
request.args.get(key, default) | 指定したキーの値を返します。キーが存在しない場合は default に指定した値を返します。 |
request.args.get(key, type=型) | 値を指定した型に変換して返します。変換に失敗した場合は None またはデフォルト値を返します。 |
request.args.getlist(key) | 同名キーの値をすべてリストで返します。同じキーが複数あるクエリパラメータの取得に使います。 |
request.args[key] | 指定したキーの値を返します。キーが存在しない場合は 400 Bad Request が発生します。 |
request.args.keys() | クエリパラメータのキー一覧を返します。 |
request.args.to_dict() | クエリパラメータを通常の辞書に変換して返します。同名キーが複数ある場合は最初の値のみが含まれます。 |
request.args.to_dict(flat=False) | 全値をリストで持つ辞書に変換して返します。同名キーが複数ある場合でも全件取得できます。 |
サンプルコード
書籍検索サイトを例に、キーワード・ページ番号・複数タグによる絞り込み機能を実装します。request.args.get() の type 引数による型変換と、getlist() による複数値取得のパターンを示します。
app.py
from flask import Flask, request, render_template
app = Flask(__name__)
books = [
{'id': 1, 'title': 'Pythonはじめの一歩', 'tags': ['python', 'beginner']},
{'id': 2, 'title': 'FlaskでWebアプリ開発', 'tags': ['python', 'flask', 'web']},
{'id': 3, 'title': 'データ分析入門', 'tags': ['python', 'data']},
{'id': 4, 'title': 'JavaScript完全攻略', 'tags': ['javascript', 'web']},
{'id': 5, 'title': 'FlaskとReactで作るSPA', 'tags': ['flask', 'javascript', 'web']},
]
BOOKS_PER_PAGE = 2
@app.route('/search/')
def search():
keyword = request.args.get('q', '').strip()
# type=int を指定すると文字列を整数に自動変換します
# 変換に失敗した場合や指定がない場合は default の 1 が使われます
page = request.args.get('page', 1, type=int)
# 同名キーを複数受け取ります
# 例: /search/?tag=python&tag=flask → ['python', 'flask']
selected_tags = request.args.getlist('tag')
result = books
if keyword:
result = [b for b in result if keyword.lower() in b['title'].lower()]
if selected_tags:
result = [
b for b in result
if all(tag in b['tags'] for tag in selected_tags)
]
if page < 1:
page = 1
total = len(result)
start = (page - 1) * BOOKS_PER_PAGE
paged_result = result[start:start + BOOKS_PER_PAGE]
has_next = (start + BOOKS_PER_PAGE) < total
return render_template(
'search.html',
books=paged_result,
keyword=keyword,
selected_tags=selected_tags,
page=page,
has_next=has_next,
)
if __name__ == '__main__':
app.run(debug=True)
templates/search.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>書籍検索</title>
</head>
<body>
<h1>書籍検索</h1>
<!-- method="get" にするとフォームの値がクエリパラメータになります -->
<form method="get" action="/search/">
<input type="text" name="q" value="{{ keyword }}" placeholder="キーワード">
<label><input type="checkbox" name="tag" value="python"
{% if 'python' in selected_tags %}checked{% endif %}> Python</label>
<label><input type="checkbox" name="tag" value="flask"
{% if 'flask' in selected_tags %}checked{% endif %}> Flask</label>
<label><input type="checkbox" name="tag" value="web"
{% if 'web' in selected_tags %}checked{% endif %}> Web</label>
<button type="submit">検索</button>
</form>
<p>{{ books | length }} 件表示中({{ page }} ページ目)</p>
<ul>
{% for book in books %}
<li>{{ book.title }} — タグ: {{ book.tags | join(', ') }}</li>
{% else %}
<li>該当する書籍が見つかりませんでした。</li>
{% endfor %}
</ul>
<div>
{% if page > 1 %}
<a href="{{ request.path }}?{{ request.query_string.decode() | replace('page=' ~ page, 'page=' ~ (page - 1)) }}">
« 前のページ
</a>
{% endif %}
{% if has_next %}
<a href="{{ request.path }}?{{ request.query_string.decode() | replace('page=' ~ page, 'page=' ~ (page + 1)) if 'page=' in request.query_string.decode() else request.query_string.decode() ~ '&page=' ~ (page + 1) }}">
次のページ »
</a>
{% endif %}
</div>
</body>
</html>
概要
request.args はFlaskの request オブジェクトが持つ属性で、URLのクエリ文字列(? 以降の部分)を解析した結果を保持しています。型はWerkzeugの ImmutableMultiDict で、通常の辞書と同様に扱えますが変更はできません。
値の取得には .get() が使われることが多いです。キーが存在しない場合でも例外を発生させず、None やデフォルト値を返します。type=int のように type 引数を渡すと型変換も同時に行えるため、ページ番号など整数が必要なパラメータの処理がシンプルになります。一方、request.args[key] の形式はキーが存在しない場合に 400 Bad Request を発生させるため、必須パラメータの検証に使えますが、エラーメッセージをカスタマイズしたい場面では .get() と組み合わせて明示的に検証するほうが柔軟に対応できます。
チェックボックスや複数選択リストのように同名のパラメータが複数ある場合は .getlist() を使います。.get() では最初の値しか取得できないため注意が必要です。取得した値はすべて文字列なので、数値や真偽値が必要な場合は型変換してから使うことが一般的です。
POSTリクエストのフォームデータを取得する場合は request.form を使います。クエリパラメータとフォームデータの両方をまとめて扱いたい場合は request オブジェクト もあわせてご覧ください。
よくあるミス
複数値を .get() で取得しようとする
チェックボックスなど同名のパラメータが複数ある場合に .get() を使うと、最初の1件しか取得できません。.getlist() を使う必要があります。
# URL: /search/?tag=python&tag=flask&tag=web
# NG: .get() では最初の値しか取れません
tags = request.args.get('tag')
print(tags)
python
# OK: .getlist() で全件取得します
tags = request.args.getlist('tag')
print(tags)
['python', 'flask', 'web']
存在しないキーに [] でアクセスして 400 エラーを発生させる
request.args['key'] の形式でキーが存在しない場合、Flaskは 400 Bad Request を返します。任意のパラメータを取得する際は .get() を使う方法がよく使われます。
# URL: /search/ (?q= の指定なし) # NG: キーが存在しないと 400 Bad Request が発生します keyword = request.args['q']
# OK: .get() ならキーがなくても None を返します
keyword = request.args.get('q')
print(keyword)
None
整数のパラメータを型変換せずに使う
クエリパラメータはすべて文字列として渡されます。数値演算や比較を行う前に型変換が必要です。type=int オプションを使うと変換と取得を1行で書けます。
# NG: page は文字列のまま。数値比較で意図しない結果になります
page = request.args.get('page', 1)
print(page + 1)
TypeError: can only concatenate str (not "int") to str
# OK: type=int を指定すると整数に変換して取得します
page = request.args.get('page', 1, type=int)
print(page + 1)
2
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。