Djangoメモ(11) : リクエスト処理の流れとURLconf (URL configuration)
A Complete Beginner's Guide to Djangoのチュートリアルを参考にリクエスト処理の流れとURLconf (URL configuration)について調べてみる。
詳細ページを表示
前回までで下図のBoard一覧を表示するページを作成したが、このページのBoard名(Django, Python, Random)をクリックしたら各BoardのTopic一覧を表示する詳細ページを作成することを考える。
Boardは複数個登録できるので、固定のURLではなくboards/1
, boards/2
といった特定パターンのURLでアクセスできるようにする必要がある。
リクエスト処理の流れ
最初にドキュメントでDjangoのリクエスト処理の流れを調べてみる。
説明にあるURLconf (URL configuration) とはpure Pythonコードのモジュールで、URLパス表記とビューの Python 関数とのマッピングを記述(urls.py
のurlpatterns
)したものである。
まず、Django は、どのモジュールをルート URLconf として使うか決定します。通常は、この値は
ROOT_URLCONF
に設定されています。ただし、 HttpRequest オブジェクトにurlconf
という属性が設定されていた場合 ( middleware で設定されます) 、その値をROOT_URLCONF
の代わりに使います。Django はその Python モジュールをロードして、
urlpatterns
という名前の変数を探します。この変数の値はdjango.urls.path()
またはdjango.urls.re_path()
インスタンスの Python リストでなければなりません。Django は URL パターンを順に調べて、リクエスト URL に最初にマッチしたところで止まります。
ある 1 個の正規表現にマッチしたら、 Django はマッピングで指定されたビューを import して呼び出します。そのビューは単純な Python 関数 (もしくは class-based view) です。ビューには以下の引数が渡されます:
- HttpRequest のインスタンス。
- マッチした URL パターンから無名グループが返された場合は、正規表現でマッチした値が位置引数として渡されます。
- URL パス表現でマッチした名前付き部分からはキーワード引数が作られます。ただし、
django.urls.path()
やdjango.urls.re_path()
に kwargs オプション引数が指定されていた場合は、その中の引数で上書きされます。もし、 URL 正規表現が何にもマッチしなかったり、パターンマッチングプロセスの途中のどこかで例外が発生した場合、Django は適切なエラーハンドリングビューを呼び出します。下の Error handling を見てください。
上記リクエスト処理の流れを現状のプロジェクトで確認してみる。
プロジェクトのsettings.py
でROOT_URLCONF = 'myproject.urls'
と定義しているので下記myproject/urls.py
がルートURLconfとして使われる。
urlpatterns
変数の値はdjango.urls.path()
のリストになっているので問題はなし。
urlpatterns = [ path('', views.home, name='home'), path('admin/', admin.site.urls), ]
ここでhttp://127.0.0.1:3000/
のようなルートにアクセスするとpath('', views.home, name='home')
にパターンがマッチするので、マッピングされたviews.home
が呼ばれることになる。
説明に「リクエスト URL に最初にマッチしたところで止まり」とあるようにマッチするパターンが複数ある場合は記述順が重要になる。
URLconf、ビュー、テンプレートの編集
ひとまず直接URLを入力して、詳細ページとしてパンくずリストを表示できるようにしてみる。
基本的にはチュートリアル通りだが、チュートリアルのDjangoバージョンは1.11でurl()
関数を使用しているため、path()
関数を使用するように変更する。
最初にmyproject/urls.py
にboards/<int:pk>/
の行を追加。
<int:pk>
のような<
, >
で囲まれた部分はURLの一部がキャプチャされキーワード引数としてビュー関数に送信される。int
部分は一致するパターンを識別するためのパスコンバータ(後述)で、pk
部分はビュー関数で参照する変数名(pk
はPrimary Keyの意味。変数名なので自由に決めて良い)になる。
from django.contrib import admin from django.urls import path from boards import views urlpatterns = [ path('', views.home, name='home'), path('boards/<int:pk>/', views.board_topics, name='board_topics'), path('admin/', admin.site.urls), ]
次にboards/views.py
にboard_topics
を追加するがboard_topics(request, pk)
のpk
はurlpatterns
で指定した変数名にする。
このpk
には、例えばhttp://127.0.0.1:3000/boards/1/
にアクセスすると1
の部分がキャプチャされるので1
がセットされる。
Board.objects.get(pk=pk)
の最初のpk
はPrimary Keyを意味し、Primary Keyで検索してオブジェクトを取得する。
モデルのPrimary Keyは明示的に定義していない場合は自動でid
というフィールドがPrimary Keyとして作成されるので、Primary Keyを定義していないBoardモデルの場合はid
と同じになる(つまりget(id=pk)
でも動作する)。
def board_topics(request, pk): board = Board.objects.get(pk=pk) return render(request, 'topics.html', {'board': board})
最後にテンプレートファイルtemplates/topics.html
を作成し、パンくずリストを表示する下記コードを記述する。
{% load static %}<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{ board.name }}</title> <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}"> </head> <body> <div class="container"> <ol class="breadcrumb my-4"> <li class="breadcrumb-item">Boards</li> <li class="breadcrumb-item active">{{ board.name }}</li> </ol> </div> </body> </html>
これで編集は完了。
boards/1/
にアクセスすると1番目に登録されているDjango
が表示され、
boards/2/
にアクセスすると2番目に登録されているPython
が表示される。
int
は数字にしかマッチしないので、例えばboards/a/
にアクセスするとPage not foundになる。
パスコンバータ
デフォルトではint
の他に下記パスコンバータが使用できる。
str
- 空でない文字列にマッチ。ただしパスのセパレータである/
は除くint
- 0または正の整数にマッチ。返り値はintslug
- スラグとは英文字と数字、アンダースコア、ハイフンだけからなる短いラベル文字列。例えばbuilding-your-1st-django-site
にマッチuuid
- UUIDフォーマットにマッチ。例えば075194d3-6885-417e-a8a8-6c931e272f00
にマッチ。返り値はUUIDインスタンスpath
- 空でない文字列にマッチ。ただしパスのセパレータである/
は含む
まとめ
- リクエスト処理の流れを確認
- URLconfはURLパス表記とビュー関数とのマッピング設定
<int:pk>
のような<
,>
で囲まれた部分はURLの一部がキャプチャされキーワード引数としてビュー関数に送信される- パスコンバータには
str
,int
,slug
,uuid
,path
がある