パスパラメータの型を指定し忘れるとどうなるか?

概要

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/ にアクセスすると、BookEditViewget() が呼ばれる。


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 を触りたての頃にも気になって調べたが、当時はドキュメントを見つけることができなかった。
おそらく、検索にひっかかるようなキーワードをうまいこと指定できていなかったり、膨大なドキュメントに圧倒されていたのだろう…。

型指定し忘れた当時のことを振り返ることで、ドキュメントの場所も知ることができた。

参考