DjangoでPageNotFound時にjsonを返す方法
Djangoでapiを作っている際に、自分で定義していないpathをリクエストしたところ404ページが表示されました。
apiを使うため、これをjsonで返すように変更したいと考えて、実現する方法を調べてみました。
参考にしたページ一覧
Error handling
https://docs.djangoproject.com/en/3.0/topics/http/urls/#error-handling
handler404
https://docs.djangoproject.com/en/3.0/ref/urls/#handler404
Customizing error views
https://docs.djangoproject.com/en/3.0/topics/http/views/#customizing-error-views
実現方法
まずはproject/urls.py
を以下のようにします。
from django.http import JsonResponse from django.urls import path, include def handle_404(request, exception): return JsonResponse({"status": "page not found."}) def handle_403(request, exception): return JsonResponse({"status": "forbidden."}) def handle_500(request): return JsonResponse({"status": "server error."}) urlpatterns = [ path('api/', include('api.urls')), ] handler403 = 'project.urls.handle_403' handler404 = 'project.urls.handle_404' handler500 = 'project.urls.handle_500'
この記述の中のhandlerXXX
が重要な部分です。
この記述はurls.py
に書くようにドキュメントにかかれています。
また、参考にできるコードはdjango.views.defaults.page_not_found
から確認できます。
import用のパスをproject.urls.handle_403
のようにしていますが、これは以下のように関数を代入しても良いです。
handler403 = handle_403 handler404 = handle_404 handler500 = handle_500
handle_404
関数についてはurls.py
に書く必要はなく、別のファイルに書いても大丈夫です。
例えば、restframework
用の例外ハンドラと同じ場所に書くのが良いと思います。
検証
検証する際にDEBUG = TRUE
ではできないのでFALSE
にします。
curl
を利用してリクエストします。
curl http://localhost:8000/api/hoge/piyo
結果
{"status": "page not found."}
このときのexception
変数のインスタンスはResolver404
でした。
404
でハンドリングしているため、Http404
で例外が出ていると予想していたのですが間違っていました。
というかdocstring
に以下のように書かれていたのでわかっていませんでした。
The message from the exception which triggered the 404 (if one was supplied), or the exception class name
なんのインスタンスなのか書いておいてほしいです。
Resolver404
だったので、api内部でraise Http404
としてもハンドラでキャッチされませんでした。
私の場合はdjangorestframework
用の例外ハンドラを用意していたので、そちらでキャッチされました。