Python Django 入門トップページ


Django REST Framework による API 開発

  1. API とプロジェクトの概要
  2. Django REST Frameworkのインストール
  3. プロジェクトの作成
  4. 基本設定
  5. アプリケーションの作成と登録
  6. モデルの作成とマイグレーション
  7. テストデータの設定
  8. コメント一覧を出力する API
  9. コメント詳細情報を出力する API
  10. 新規投稿と更新・削除の API
  11. ページネーション
  12. 入力内容の検証(バリデーション)
  13. テストの自動化
  14. Shell でのユーザ登録
  15. Fixtures でのユーザ登録
  16. ユーザ認証を必須にする
  17. コメントにオーナ情報を追加
  18. 権限の設定:Case #1
  19. 権限の設定:Case #2
  20. Python から API への接続
  21. React アプリケーションからの API 接続と CORS エラーの回避

Django REST Framework による API 開発

権限の設定:Case #1

このページと次のページではここのコメントに対する権限について次の2つのケースを想定して設定します.

このページでは Case #1 を想定した設定を行います.まず,comments アプリケーション内に permissions.py というファイルを作成し,このページのExample にあるような内容を記載します.具体的には,IsOwnerOrReadOnly 関数ではオブジェクトへのアクセスが GET などの安全なメソッドである場合には許可し,それ以外のメソッドについてはオブジェクトの所有者とログインユーザが一致する場合に許可をする設定を行なっています.

comments\permissions.py
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Object-level permission to only allow owners of an object to edit it.
    Assumes the model instance has an `owner` attribute.
    """
    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        return obj.owner == request.user

次に views.py を編集して,上で定義した IsOwnerOrReadOnlyIsAuthenticatedOrReadOnly を併用して目的の権限を実現します.

comments\views.py
from django.shortcuts import render
from rest_framework import generics
from rest_framework import permissions
from .models import Comment
from .serializers import CommentSerializer
from .paginations import LargeResultsSetPagination
from .permissions import IsOwnerOrReadOnly

# Create your views here.

class CommentList(generics.ListCreateAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    pagination_class = LargeResultsSetPagination
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

class CommentDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]

では実際に目的の権限を設定できているか確認します.まず認証情報を与えることなく全てのユーザのコメントを一覧で表示することができます.

...\django_comment_api>curl http://127.0.0.1:8000/comments/ ⏎
{"count":12,"next":"http://127.0.0.1:8000/comments/?page=2","previous":null,"results":[{"id":12,"owner_id":2,"title":"owner","body":"store owner_id","updated_at":"2023-11-23T17:28:50.507987"},{"id":11,"owner_id":1,"title":"owner","body":"store owner_id","updated_at":"2023-11-23T17:28:40.544771"}]}

コメントの詳細情報の閲覧も認証情報を与えることなく可能です.

...\django_comment_api>curl http://127.0.0.1:8000/comments/2/ ⏎
{"id":2,"owner_id":2,"title":"2個目のコメント","body":"コメントの本文2","updated_at":"2023-11-23T11:02:00"}

認証情報を与えなければ,新規投稿や編集は不可能です.

...\django_comment_api>curl -X POST -d "title=permission" -d "body=permissions" http://127.0.0.1:8000/comments/ ⏎
{"detail":"認証情報が含まれていません。"}
...\django_comment_api>curl -X PUT -d "title=edit" -d "body=body edit" http://127.0.0.1:8000/comments/1/ ⏎
{"detail":"認証情報が含まれていません。"}

次に,正しい認証情報を与えた場合も全てのユーザのコメントを一覧で表示することができます.

...\django_comment_api>curl -u user_a:password http://127.0.0.1:8000/comments/ ⏎
{"count":12,"next":"http://127.0.0.1:8000/comments/?page=2","previous":null,"results":[{"id":12,"owner_id":2,"title":"owner","body":"store owner_id","updated_at":"2023-11-23T17:28:50.507987"},{"id":11,"owner_id":1,"title":"owner","body":"store owner_id","updated_at":"2023-11-23T17:28:40.544771"}]}

もちろん自身で投稿したコメントの詳細情報は確認できます.

...\django_comment_api>curl -u user_a:password http://127.0.0.1:8000/comments/1/ ⏎
{"id":1,"owner_id":1,"title":"最初のコメント","body":"コメントの本文","updated_at":"2023-11-23T11:01:00"}

他のユーザが投稿したコメントも同様に詳細情報を確認できます.

...\django_comment_api>curl -u user_a:password http://127.0.0.1:8000/comments/2/ ⏎
{"id":2,"owner_id":2,"title":"2個目のコメント","body":"コメントの本文2","updated_at":"2023-11-23T11:02:00"}

認証情報を与えると新規の投稿が可能で,投稿されたコメントには自身の owner_id がセットされます.

...\django_comment_api>curl -X POST -d "title=permission" -d "body=permissions" -u user_a:password http://127.0.0.1:8000/comments/ ⏎
{"id":13,"owner_id":1,"title":"permission","body":"permissions","updated_at":"2023-11-23T17:41:38.364189"}

自分自身が投稿したコメントは更新(あるいは削除も)することが可能です.

...\django_comment_api>curl -X PUT -d "title=edit" -d "body=body edit" -u user_a:password http://127.0.0.1:8000/comments/1/ ⏎
{"id":1,"owner_id":1,"title":"edit","body":"body edit","updated_at":"2023-11-23T17:42:58.795269"}

他のユーザが投稿したコメントを更新する権限はありません.

...\django_comment_api>curl -X PUT -d "title=edit" -d "body=body edit" -u user_a:password http://127.0.0.1:8000/comments/2/ ⏎
{"detail":"このアクションを実行する権限がありません。"}
...\django_comment_api>

目次に戻る