$30 off During Our Annual Pro Sale. View Details »

Django REST Framework はじめの一歩 〜 押さえておきたい3つのポイント 〜 / First step of Django REST Framework (stapy#87 2022)

akiyoko
November 10, 2022

Django REST Framework はじめの一歩 〜 押さえておきたい3つのポイント 〜 / First step of Django REST Framework (stapy#87 2022)

Django で RESTful な API バックエンドを構築するとなれば「Django REST Framework(DRF)」パッケージを使うのがほぼデファクトになっています。このトークでは、Django は少し知っているけど DRF は未経験という方をターゲットに、これだけは押さえておきたい3つのポイントについて解説します。

2022.11.10 みんなのPython勉強会#87
https://startpython.connpass.com/event/263565/

akiyoko

November 10, 2022
Tweet

More Decks by akiyoko

Other Decks in Programming

Transcript

  1. Django REST Framework はじめの⼀歩 〜 押さえておきたい3つのポイント 〜 2022.11.10 みんなのPython勉強会#87 横瀬

    明仁(akiyoko)
  2. ⽬次 1. はじめに 2. DRF とは? 3. ポイント①:全体像を把握しよう 4. ポイント②:シリアライザはフォームっぽく使える

    5. ポイント③:起点は DRF ⽤ビュー 6. まとめ 1 ( 2 min ) ( 5 min ) ( 5 min ) ( 5 min ) ( 7 min ) ( 1 min ) ※ 本トークのコードは Django 3.2 LTS / DRF 3.14 で動作確認
  3. ⾃⼰紹介 ⾃費出版本 : 2 『現場で使える Django の教科書《基礎編》』 『現場で使える Django の教科書《実践編》』

    『現場で使える Django REST Framework の教科書』 『現場で使える Django 管理サイトのつくり⽅』 名前 : 横瀬 明仁(akiyoko) 名前 : Python / Django 推しのバックエンドエンジニア Twitter : @aki_yok ブログ : akiyoko blog(https://akiyoko.hatenablog.jp/) Django 歴 : 9年くらい
  4. トークの⽬的 3 Django REST Framework(DRF)がどんなものかを ざっくり理解しよう %3'φχϞϫΧϥφΠ %3'׬શʹཧղͨ͠

  5. 皆さん DRF、使ってますか? 4

  6. Django 開発者の「73%」が DRF を使っている 5 akiyoko 独⾃アンケート (2022年10⽉実施) Q.DRF(Django REST

    Framework)を使っていますか?(N=97)
  7. お気に⼊り Django パッケージランキングで DRF が1位! 6 Q.What are your 5

    favorite third-party Django packages? (N>7000) https://lp.jetbrains.com/django-developer-survey-2021-486/ Django Developers Survey 2021 7000名を超えるアンケートで 「djangorestframework」が ナンバーワン Django パッケージに 選出される
  8. DRF って何? 7

  9. DRF とは? 8 DRF(Django REST Framework)は REST API を作成する際の多彩なニーズに応えるための 超ド定番

    Django パッケージ • Django 単体では不⾜している機能を DRF で補完 • Django 開発者が理解しやすい作り 特徴
  10. • スマホや SPA のバックエンドとして REST API がよく利⽤される • フロントエンド/バックエンド開発者が理解しやすいシンプルな設計 •

    共通の枠組みを介してフロントエンドとバックエンドを疎結合化 • リソース中⼼の設計で、モデル中⼼の Django と親和性が⾼い REST API の利⽤イメージ 9 スマホアプリ / SPA /books/1/ ボディ { "price": 2000 } PUT HTTPメソッド U R L REST API ボディ 201(Created) ステータス { "id": 1, "title": "DRFの本", "price": 2000 } HTTPメソッドでリソースへの操作を表す https://example.com/api/v1/books/1/ URI でリソースを特定 PUT 【 REST API の例 】 JSON リクエスト JSON レスポンス DRF アプリケー ション
  11. DRF が得意なこと 10 単⼀リソースの CRUD を処理する REST API なら超簡単!! 表1.REST

    API の例 ⇒ 最短 20⾏くらいで書ける!(モデル除く)
  12. 【よくある誤解①】DRF では単⼀リソースを扱う API 以外は作れない 11 • リソースがネストした API • 独⾃アクションを追加した

    API • リソースに紐付いていない API 作れる! 表2.リソースがネストした API の例 表3.独⾃アクションを追加した API の例 表4.リソースに紐付いていない API の例 (が、詳細については本トークの範囲外)
  13. 【よくある誤解②】DRF なしでは JSON のやり取りができない 12 import json from django.forms.models import

    model_to_dict from django.http.response import JsonResponse from django.views.generic import View from shop.models import Book class BookListCreateView(View): """本モデルの登録APIクラス""" def post(self, request, *args, **kwargs): """本モデルの登録API⽤のメソッド""" data = json.loads(request.body) # バリデーションを実⾏ if not data.get('title'): return JsonResponse({'message': 'タイトルは必須です。'}, status=400) # モデルオブジェクトを登録 book = Book(**data) book.save() # レスポンスオブジェクトを作成して返す return JsonResponse(model_to_dict(book), status=201) ⇒ 共通化したいというニーズから DRF が誕⽣した (できれば Django っぽい書き⽅で) (んだと思う) Ͱ͖ͳ͘ͳ͍͚Ͳɺ ਖ਼௚͠ΜͲ͍ͳ ʜ api/views.py ⼊⼒データとなる JSON⽂字列 (request.body)をパースして バリデーションを実⾏し、モデ ルオブジェクトにデータを詰め 替えて永続化して、最後に JsonResponse を返す
  14. メリット 13 • Django のノウハウやエコシステムが活⽤できる • ⼈気があり、枯れている • 公式ドキュメントやチュートリアルが充実(英語のみ) •

    機能が充実している • Cookie認証・トークン認証・JWT認証 (*) など API でよく利⽤される認証 • パーミッション(アクセス権制御) • フィルタリング(クエリ⽂字列による検索) • ページネーション(ページ表⽰に対応した JSON レスポンス) • スロットリング(利⽤回数制限) • 画⾯で API を実⾏確認できるテストクライアント(Browsable API) • OpenAPI に準拠した API ドキュメントを出⼒ (*) DRF 外のパッケージが必要 %3'͕͋Ε͹ ԿͰ΋Ͱ͖Δʂ
  15. デメリット 14 レスポンス の返却 View View View View モデル データベース

    ビューの 呼び出し データベース操作 クエリ 発⾏ バリデーション・ フォームの組み⽴て URLconf 通常の Django ⽤ ビュー View View フォーム URLパターン の登録 ビューの 呼び出し View View View View テンプレー ト View View シリアライ ザ バリデーション・ JSONの組み⽴て HTMLコードの組み⽴て DRF ⽤ ビュー U R L デ % ス パ ( チ * ミ ド ル ウ / ア DRFプロジェクト の全体像 ෳࡶ リクエスト レスポンス %KBOHP͚ͩͰ΋ ෳࡶͳͷʹʜ
  16. そこで・・ 15

  17. 押さえておきたい3つのポイント 16 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー

  18. 17 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー

  19. 全体像と登場⼈物(通常の Django プロジェクト) 18 View View View View モデル ビューの

    呼び出し データベース操作 バリデーション・ フォームの組み⽴て URLconf 通常の Django ⽤ ビュー View View フォーム URLパターン の登録 View View テンプレー ト HTMLコードの組み⽴て U R L デ % ス パ ( チ * ミ ド ル ウ / ア Django プロジェクトの全体像 コンポーネント 概要 URLディスパッ チャ URLconf にしたがってリクエストURLに応じたビュー 関数を呼び出す。ビュー関数からのレスポンスや例外の ハンドリングもおこなう URLconf URLパターンとビュー関数のマッチング情報などを保持 したモジュール ミドルウェア リクエストの前処理とレスポンスの後処理をおこなう ビュー モデルやフォーム、テンプレートと連携してレスポンス を作成する フォーム ⼊⼒フォームのデータをオブジェクトとして扱うための ⼊れ物。⼊⼒データのバリデーションもおこなう モデル モデルクラスとテーブルの定義を紐付ける ORM として の機能を提供 テンプレート 特別な記法で動的に変更する内容を記述できるHTML ファイル レスポンス の返却 表5.Django プロジェクトの登場⼈物
  20. 全体像と登場⼈物(DRF プロジェクト) 19 レスポンス の返却 View View View View モデル

    ビューの 呼び出し データベース操作 バリデーション・ フォームの組み⽴て URLconf 通常の Django ⽤ ビュー View View フォーム URLパターン の登録 ビューの 呼び出し View View View View テンプレー ト View View シリアライ ザ バリデーション・ JSONの組み⽴て HTMLコードの組み⽴て DRF ⽤ ビュー U R L デ % ス パ ( チ * ミ ド ル ウ / ア リクエスト レスポンス DRF プロジェクトの全体像 起点 コンポーネント 概要 URLディスパッ チャ Django と同じ URLconf Django と同じ ミドルウェア Django と同じ ビュー DRF の起点となる DRF⽤のビュー。モデルやシリアラ イザと連携してレスポンスを作成する フォーム 使わない(共存も可能) モデル Django と同じ テンプレート 使わない(共存も可能) シリアライザ ⼊出⼒となる JSON データをオブジェクトとして扱うた めのクラス。⼊⼒データのバリデーションもおこなう。 使い⽅はフォームと類似 表6.DRF プロジェクトの登場⼈物
  21. ポイント① まとめ:全体像を把握しよう 20 DRF では • DRF⽤のビュー を作成して URLconf に登録

    • シリアライザ を使う • ⼊出⼒の JSON(およびモデルとの連携)定義とバリデーションを担当 • フォームとテンプレートは使わない それ以外は通常の Django とだいたい同じ
  22. 21 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー

  23. シリアライザの使いどころ 22 シリアライザは • ⼊⼒データのバリデーション • (モデルオブジェクトの永続化) • 出⼒データの作成 を担当

    バリデーションOKの場合 ビュー JSON レスポンス (正常) バリデーションNGの場合 JSON レスポンス (400 エラー) URLディスパッチャ モデルオブジェクトを登録・更新・削除 シリアライザオブジェクトからレスポンスオブジェクトを作成 シリアライザオブジェクトを作成 登録 API 更新・⼀部更新 API 削除 API 取得(詳細) API バリデーションを実⾏ 取得(⼀覧) API pk pk pk クエリ⽂字列 JSON レスポンス (404 エラー) リソースが⾒つからない場合 (pk やクエリ⽂字列を使って)モデルオブジェクトを取得 シリアライザオブジェクトを作成 S M シリアライザ モデル = = S S M S S S M /
  24. シリアライザはフォームっぽく使える 23 モデルと紐付いた REST API の場合は rest_framework.serializers.ModelSerializer を使うのが簡単 • 使い⽅は

    ModelForm とほぼ同じ • バリデーションメソッドは「is_valid」、 永続化メソッドは「save」 • バリデーション済みのデータは 「validated_data」にアクセス (フォームと 変数名が異なるので注意) ModelForm cleaned_data 値をセット errors 属性 属性 ModelSerializer validated_data 値をセット errors 属性 属性 シリアライザ ⼊⼒データ モデル オブジェクト ⼊⼒データ モデル オブジェクト フォーム (更新時) (更新時) data 引数 data 引数 instance 引数 instance 引数 バ リ デ $ シ & ン バ リ デ $ シ & ン 永続化 永続化
  25. シリアライザの利⽤イメージ 24 from rest_framework import serializers from shop.models import Book

    class BookSerializer(serializers.ModelSerializer): """本モデル⽤シリアライザ""" class Meta: model = Book fields = ['id', 'title', 'price'] # fields = '__all__' # exclude = ['created_at'] api/serializers.py >>> from api.serializers import BookSerializer >>> serializer = BookSerializer(data={'title': 'DRFの本', 'price': 1000}) >>> serializer.is_valid() True >>> serializer.validated_data OrderedDict([('title', 'DRFの本'), ('price', 1000)]) >>> book = serializer.save() >>> serializer = BookSerializer(instance=book, data={'price': 2000}, partial=True) >>> serializer.is_valid() True >>> serializer.save() <Book: DRFの本> 利⽤⽅法 ModelSerializer validated_data 値をセット errors 属性 属性 ⼊⼒データ モデル オブジェクト (更新時) data 引数 instance 引数 バ リ デ $ シ & ン 永続化 登録時は引数 data に⼊⼒データを渡す 更新時は引数 instance にモデル オブジェクト、引数 data に⼊⼒ データを渡す (partial=True は⼀部更新)
  26. ポイント② まとめ:シリアライザはフォームっぽく使える 25 • モデルと紐付いた REST API の場合は ModelSerializer を

    使うのが簡単 • 使い⽅は ModelForm とほぼ同じ
  27. 26 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー

  28. APIView とは? 27 • APIView を継承することで、さまざまな前処理 と後処理をやってくれる • 2. 〜

    6. は差し替え可能(プラガブル) • 設定ファイルの「REST_FRAMEWORK」で全体設 定、クラス変数をオーバーライドしてビュークラス 単位での個別設定が可能 APIView を継承したビュー APIView による 前処理 ビューの処理 APIView による 後処理 7. 例外ハンドリング 1. リクエストオブジェクトを DRF ⽤に変換 2. レンダラクラスとメディアタイプを決定 3. バージョニング 4. 認証チェック 5. パーミッションチェック 6. スロットリング rest_framework.views.APIView は DRF の起点となる基底ビュークラス
  29. DRF ⽤のビューは3種類 28 DRF ⽤ビューは、⽤途に応じて 1)〜 3)のいずれかを継承して作成 1)rest_framework.views.APIView 2)rest_framework.generics.CreateAPIView などの

    汎⽤ APIView 3) rest_framework.viewsets.ModelViewSet 系ビュー カスタム性 コード量 少 多 Django DRF django.views.generic.base View (汎⽤ APIView) ReadOnlyModelViewSet rest_framework.viewsets ModelViewSet または rest_framework.generics CreateAPIView など どちらも APIView の⼦クラス rest_framework.views APIView GenericAPIView rest_framework.generics ⼩ ⼤
  30. 1)APIView を継承したビューの書き⽅ 29 コードは⻑くなるが、 カスタマイズしやすい from rest_framework import status, views

    from rest_framework.generics import get_object_or_404 from rest_framework.response import Response from shop.models import Book from .serializers import BookSerializer class BookRetrieveUpdateAPIView(views.APIView): """本モデルの取得(詳細)・更新・⼀部更新・削除APIクラス""" def get(self, request, pk, *args, **kwargs): """本モデルの取得(詳細)APIに対応するハンドラメソッド""" # モデルオブジェクトを取得 book = get_object_or_404(Book, pk=pk) # シリアライザオブジェクトを作成 serializer = BookSerializer(instance=book) return Response(serializer.data, status.HTTP_200_OK) def put(self, request, pk, *args, **kwargs): """本モデルの更新APIに対応するハンドラメソッド""" # モデルオブジェクトを取得 book = get_object_or_404(Book, pk=pk) # シリアライザオブジェクトを作成 serializer = BookSerializer(instance=book, data=request.data) # バリデーションを実⾏ serializer.is_valid(raise_exception=True) # モデルオブジェクトを更新 serializer.save() # レスポンスオブジェクトを作成して返す return Response(serializer.data, status.HTTP_200_OK) (以下略) api/views.py 例えば更新 API では、モデルオブジェクトと ⼊⼒データからシリアライザオブジェクトを 作成し、is_valid() で⼊⼒データのバリデー ションをおこない、save() でモデルオブジェ クトを更新して、最後にシリアライザの data 属性の値を使ってレスポンスオブジェクトを 作成して返す
  31. 2)汎⽤ APIView を継承したビューの書き⽅ 30 • 対応アクションごとに汎⽤ APIView が ⽤意されている •

    queryset(モデルオブジェクトを取得する ためのクエリ)と serializer_class(シリ アライザクラス)と を指定するだけ from rest_framework import generics from shop.models import Book from .serializers import BookSerializer class BookListCreateAPIView(generics.ListCreateAPIView): """本モデルの取得(⼀覧)・登録APIクラス""" queryset = Book.objects.all() serializer_class = BookSerializer class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView): """本モデルの取得(詳細)・更新・⼀部更新・削除APIクラス""" queryset = Book.objects.all() serializer_class = BookSerializer api/views.py 表7.汎⽤ APIView の種類と対応アクション from django.urls import path from api import views urlpatterns = [ path('api/books/', views.BookListCreateAPIView.as_view()), path('api/books/<pk>/', views.BookRetrieveUpdateDestroyAPIView.as_view()), ] config/urls.py (*) CreateAPIView では queryset は不要 (*)
  32. 3)ModelViewSet 系ビューを継承したビューの書き⽅ 31 • serializer_class と queryset の指定が必須 • ViewSet

    ⽤の Router(SimpleRouter または DefaultRouter)を利⽤して URL パターンを URLconf に追加 from rest_framework import viewsets from shop.models import Book from .serializers import BookSerializer class BookViewSet(viewsets.ModelViewSet): """本モデルのCRUD⽤APIクラス""" serializer_class = BookSerializer queryset = Book.objects.all() api/views.py from django.urls import include, path from rest_framework import routers from api import views router = routers.DefaultRouter() router.register('books', api.BookViewSet) urlpatterns = [ # すべてのアクション(⼀覧・詳細・登録・更新・⼀部更新・削除)をまとめて追加 path('api/', include(router.urls)), ] config/urls.py 表8.ModelViewSet 系ビューの対応アクションメソッド 単⼀モデルの CRUD を処理する REST API を まるっと実装したい場合に最適
  33. ポイント③ まとめ:起点は DRF ⽤ビュー 32 • 単⼀モデルの CRUD を処理する REST

    API をまるっと実装したい場合 は、 ModelViewSet 系ビュー を使うのが⼀番簡単 • ViewSet ⽤ Router と⼀緒に使う • 複雑なことがしたい場合は、APIView(または GenericAPIView)を 継承したビュークラスを使う
  34. まとめ 33 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー 『現場で使える Django REST

    Framework の教科書』 (紙の本) (電⼦版) 2022年12⽉ 改訂 !! Django 3.2 / DRF 3.14 対応、Vue 3 + Vuetify 3 でチュートリアル刷新 DRF のことをもっと知りたい⽅は、この本がオススメ!!