Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

⽬次 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 で動作確認

Slide 3

Slide 3 text

⾃⼰紹介 ⾃費出版本 : 2 『現場で使える Django の教科書《基礎編》』 『現場で使える Django の教科書《実践編》』 『現場で使える Django REST Framework の教科書』 『現場で使える Django 管理サイトのつくり⽅』 名前 : 横瀬 明仁(akiyoko) 名前 : Python / Django 推しのバックエンドエンジニア Twitter : @aki_yok ブログ : akiyoko blog(https://akiyoko.hatenablog.jp/) Django 歴 : 9年くらい

Slide 4

Slide 4 text

トークの⽬的 3 Django REST Framework(DRF)がどんなものかを ざっくり理解しよう %3'φχϞϫΧϥφΠ %3'׬શʹཧղͨ͠

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

お気に⼊り 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 パッケージに 選出される

Slide 8

Slide 8 text

DRF って何? 7

Slide 9

Slide 9 text

DRF とは? 8 DRF(Django REST Framework)は REST API を作成する際の多彩なニーズに応えるための 超ド定番 Django パッケージ • Django 単体では不⾜している機能を DRF で補完 • Django 開発者が理解しやすい作り 特徴

Slide 10

Slide 10 text

• スマホや 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 アプリケー ション

Slide 11

Slide 11 text

DRF が得意なこと 10 単⼀リソースの CRUD を処理する REST API なら超簡単!! 表1.REST API の例 ⇒ 最短 20⾏くらいで書ける!(モデル除く)

Slide 12

Slide 12 text

【よくある誤解①】DRF では単⼀リソースを扱う API 以外は作れない 11 • リソースがネストした API • 独⾃アクションを追加した API • リソースに紐付いていない API 作れる! 表2.リソースがネストした API の例 表3.独⾃アクションを追加した API の例 表4.リソースに紐付いていない API の例 (が、詳細については本トークの範囲外)

Slide 13

Slide 13 text

【よくある誤解②】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 を返す

Slide 14

Slide 14 text

メリット 13 • Django のノウハウやエコシステムが活⽤できる • ⼈気があり、枯れている • 公式ドキュメントやチュートリアルが充実(英語のみ) • 機能が充実している • Cookie認証・トークン認証・JWT認証 (*) など API でよく利⽤される認証 • パーミッション(アクセス権制御) • フィルタリング(クエリ⽂字列による検索) • ページネーション(ページ表⽰に対応した JSON レスポンス) • スロットリング(利⽤回数制限) • 画⾯で API を実⾏確認できるテストクライアント(Browsable API) • OpenAPI に準拠した API ドキュメントを出⼒ (*) DRF 外のパッケージが必要 %3'͕͋Ε͹ ԿͰ΋Ͱ͖Δʂ

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

そこで・・ 15

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

全体像と登場⼈物(通常の 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 プロジェクトの登場⼈物

Slide 20

Slide 20 text

全体像と登場⼈物(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 プロジェクトの登場⼈物

Slide 21

Slide 21 text

ポイント① まとめ:全体像を把握しよう 20 DRF では • DRF⽤のビュー を作成して URLconf に登録 • シリアライザ を使う • ⼊出⼒の JSON(およびモデルとの連携)定義とバリデーションを担当 • フォームとテンプレートは使わない それ以外は通常の Django とだいたい同じ

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

シリアライザの使いどころ 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 /

Slide 24

Slide 24 text

シリアライザはフォームっぽく使える 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 引数 バ リ デ $ シ & ン バ リ デ $ シ & ン 永続化 永続化

Slide 25

Slide 25 text

シリアライザの利⽤イメージ 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() 利⽤⽅法 ModelSerializer validated_data 値をセット errors 属性 属性 ⼊⼒データ モデル オブジェクト (更新時) data 引数 instance 引数 バ リ デ $ シ & ン 永続化 登録時は引数 data に⼊⼒データを渡す 更新時は引数 instance にモデル オブジェクト、引数 data に⼊⼒ データを渡す (partial=True は⼀部更新)

Slide 26

Slide 26 text

ポイント② まとめ:シリアライザはフォームっぽく使える 25 • モデルと紐付いた REST API の場合は ModelSerializer を 使うのが簡単 • 使い⽅は ModelForm とほぼ同じ

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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 ⼩ ⼤

Slide 30

Slide 30 text

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 属性の値を使ってレスポンスオブジェクトを 作成して返す

Slide 31

Slide 31 text

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//', views.BookRetrieveUpdateDestroyAPIView.as_view()), ] config/urls.py (*) CreateAPIView では queryset は不要 (*)

Slide 32

Slide 32 text

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 を まるっと実装したい場合に最適

Slide 33

Slide 33 text

ポイント③ まとめ:起点は DRF ⽤ビュー 32 • 単⼀モデルの CRUD を処理する REST API をまるっと実装したい場合 は、 ModelViewSet 系ビュー を使うのが⼀番簡単 • ViewSet ⽤ Router と⼀緒に使う • 複雑なことがしたい場合は、APIView(または GenericAPIView)を 継承したビュークラスを使う

Slide 34

Slide 34 text

まとめ 33 ポイント①:全体像を把握しよう ポイント②:シリアライザはフォームっぽく使える ポイント③:起点は DRF ⽤ビュー 『現場で使える Django REST Framework の教科書』 (紙の本) (電⼦版) 2022年12⽉ 改訂 !! Django 3.2 / DRF 3.14 対応、Vue 3 + Vuetify 3 でチュートリアル刷新 DRF のことをもっと知りたい⽅は、この本がオススメ!!