パスパラメータの型を指定し忘れるとどうなるか?
概要
Django の URLconf (urls.py) でパスパラメータを指定する際、<int: hoge>
のように型を指定するが、
以前、型指定を忘れてしまったことがあった。
型指定を忘れるとどのような挙動となり、どのような問題があるのだろう? 🤔
気になったので調べてみた。
まえおき
ここに登場するコードは以下で実装されたものを前提としている。
- 言語: Python 3.11
- フレームワーク/ライブラリ: Django 4.2
- 参照として記載しているリンクについて: Django 4.2 のドキュメントに日本語訳がない場合は 5.1 のドキュメントのリンクを貼っている
例やコードは、サンプル向けにアレンジしたもののため、違和感はご愛嬌。
URLconf のパスパラメータについて
URLconf のパスパラメータは、 <コンバータ: パターン名>
の形で定義する。
コンバータには、マッチさせたい型を指定する。指定した型に変換された値がビュー関数に渡される。
コンバータを指定しない場合は、デフォルトで str
が指定される。
パターン名には、任意の名前を指定する。たとえば、URL に書籍idを含める場合は book_id
のような名前が適切だろう。
ここで指定した名前がキーワード引数としてビュー関数に渡される。
question_id=34 の部分は int:question_id から来ています。 山括弧を使用すると、URLの一部が「キャプチャ」され、キーワード引数としてビュー関数に送信します。 文字列の :question_id 部分は、一致するパターンを識別するために使用される名前を定義し、 int 部分は、URLパスのこの部分に一致するパターンを決定するコンバータです。 コロン (:) はコンバータとパターン名を区切ります。 はじめての Django アプリ作成、その 3> もっとビューを書いてみる
Django > はじめての Django アプリ作成、その 3> もっとビューを書いてみる
角括弧の中には、変換器の仕様(例えば、 int:section の int 部分)のように、 マッチする文字を制限したり、ビューに渡される変数の型を変更したりすることができます。 例えば、int:section は10進数の数字の文字列にマッチし、その値を
int
に変換します。 URLconf で使用するための django.urls 関数 > path() > route
Django > URLconf で使用するための django.urls 関数 > path() > route
コンバータに指定できるもの
コンバータに指定できる値はデフォルトでは以下。
str
: パスの区切り文字/
を除いて、空でない文字列にマッチ。デフォルト。int
: 0または任意の正の整数にマッチ。int
を返す。slug
: ASCII、数字、ハイフン、アンダースコアからなるスラグ文字列にマッチ。- スラグ文字とは、URL の末尾に付与するパスで、通常はそのページの内容が予想できるような文字列を指定する。
- 例えば、neko-kaburi のこのページだと、
https://neko-kaburi.lol/2025/01/25/
の後ろの記事タイトル部分がスラグ文字になる。 - 参考: Django > 用語集
uuid
: UUIDにマッチ。 UUID インスタンスを返す。path
: パスの区切り文字である/
を含む、空ではない文字列にマッチ。str
では/
が除かれるが、path
の場合は除かれない。
実際に確かめてみよう
コンバータに int
を指定した場合と、何も指定しなかった場合の挙動を見てみる。
URLConf に以下のような path を定義した。
path(
"book/<int:book_id>/edit/",
BookEditView.as_view(),
name="book_edit",
),
book/1/edit/
にアクセスすると、BookEditView
の get()
が呼ばれる。
class BookEditView(View):
"""書籍編集"""
def get(self, request, book_id):
print(type(book_id))
引数の book_id
の型を print してみると、<class 'int'>
が出力された。
次に、コンバータの int
を外して <book_id>
にし、同じように print してみたところ、<class 'str'>
が出力された。
型指定を忘れるとどんなことが起こり得るか?
ただテンプレートを返すだけならとくに問題にはならないだろう。
受け取ったパスパラメータを使って計算などをする場合には、適切に型を指定する必要がある。
例えば、<str: id>
で受け取った id を使って id * 2
という計算をする場合 (することはないと思うが)、id
は文字列なので id=1
が渡った場合の計算結果は 11
になる。
また、<int: id>
を指定した場合は、id
は整数を期待するので、book/id/edit/
のような URL にアクセスしても Page not found
となる (book/1/edit/
のような数字を期待するため)。
コンバータを指定しない場合はデフォルトで str
となるが、以下のような場合を考えると、明示的に str
を指定しておくとよさそうに思う。
- 必ずしも、コードを読む人全員がデフォルト値を認識しているとは限らない
- デフォルト値について検索する必要が出る
- コンバータを省略したコードがコピペされて、ペーストした先で型指定を忘れた場合、バグの原因になるかもしれない
- 大したコード量でもないので、明示的に指定しておくとよいのでは (そのほうが可読性もよいと思う)
おわり
今回調べたことは、Django を触りたての頃にも気になって調べたが、当時はドキュメントを見つけることができなかった。
おそらく、検索にひっかかるようなキーワードをうまいこと指定できていなかったり、膨大なドキュメントに圧倒されていたのだろう…。
型指定し忘れた当時のことを振り返ることで、ドキュメントの場所も知ることができた。