Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Django REST Frameworkに再挑戦 その5

概要

Django REST Frameworkに再挑戦 その5

参考サイト

www.django-rest-framework.org

www.codingforentrepreneurs.com

Custom Permissions

  • api/views.pyに、permissionのメソッドを追加する。めっちゃあるな!

公式サイト permissions:

Permissions - Django REST framework

from rest_framework.permissions import (
    AllowAny,
    IsAuthenticated,
    IsAdminUser,
    IsAuthenticatedOrReadOnly,
    )
  • createAPIviewで試してみる。
class PostCreateAPIView(CreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostCreateUpdateSerializer
    permission_classes = [IsAuthenticated]

    def perform_create(self, serializer):
        serializer.save(user=self.request.user, title='my title')
  • ゲストウィンドウなどで、ログインしてない状態でcreateviewを開いてみる。"detail": "Authentication credentials were not provided."と表示されていればOK!

  • adminuserのみにしたい場合は、以下のように設定する。IsAdminUserを追記するだけ。

class PostCreateAPIView(CreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostCreateUpdateSerializer
    permission_classes = [IsAuthenticated, IsAdminUser]
  • UpdateViewにも同様に、permissionをつける。
class PostUpdateAPIView(RetrieveUpdateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostCreateUpdateSerializer
    lookup_field = 'slug'
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)
  • userが投稿したpostのみを表示する。そのためにまずは、api/permissions.pyを作成して、カスタムしたpermissionのclassを作成する。

公式サイト:custom permission:

Permissions - Django REST framework

from rest_framework.permissions import BasePermission


class IsOwnerOrReadOnly(BasePermission):
    message = 'You must be the owner of this object.'
    def has_object_permission(self, request, view, obj):
        return obj.user == request.user # True or Falseを返す
  • 上記のIsOwnerOrReadOnly classを、他のpermission classと同じように指定する。これでuserがオーナーの記事しか編集できなくなる。(readは可能)
class PostUpdateAPIView(RetrieveUpdateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostCreateUpdateSerializer
    lookup_field = 'slug'
    permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]
  • 公式サイトから、SAFE_METHODSを使ったpermissionを追記してみる。編集するのは、permissions.py。
class IsOwnerOrReadOnly(BasePermission):
    message = 'You must be the owner of this object.'
    def has_object_permission(self, request, view, obj):
        my_safe_method = ['PUT']
        if request.method in my_safe_method:#もしくは、if request.method in permissions.SAFE_METHODS:
            return True
        return obj.user == request.user # True or Falseを返す
  • さらに修正してみる。
class IsOwnerOrReadOnly(BasePermission):
    message = 'You must be the owner of this object.'
    my_safe_method = ['PUT']

    # 2つとも同じ意味。。。なはず。request.methodのなかに、'PUT'がある場合は、Trueを返すという関数
    def has_permission(self, request, view):
        if request.method in self.my_safe_method:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if request.method in self.my_safe_method:
            return True
        return obj.user == request.user 
  • SAFE_METHOD は、上記のmy_safe_methodと同じ意味のもの?そのため、SAFE_METHODをimportして利用すると以下のようになる。permissions.pyを編集する。
    def has_object_permission(self, request, view, obj):
        if request.method in SAFE_METHODS:
            return True
        return obj.user == request.user # True or Falseを返す
  • ただし、このままでは、エラーが出て表示されない。my_safe_method に、GETも追加する。最終的にここでは以下のように設定する。
from rest_framework.permissions import BasePermission, SAFE_METHODS


class IsOwnerOrReadOnly(BasePermission):
    message = 'You must be the owner of this object.'
    my_safe_method = ['GET','PUT']

    def has_permission(self, request, view):
        if request.method in self.my_safe_method:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        #member = Membership.objects.get(user=request.user)
        #member.is_active
        if request.method in SAFE_METHODS:
            return True
        return obj.user == request.user # True or Falseを返す
  • Custom Permisionはよくわからなかったので、公式サイトの重要と思われる箇所を読んでみる。
To implement a custom permission, override BasePermission and implement either, or both, of the following methods:
# カスタムパーミッションを実装するには、BasePermissionと以下のメソッドのどちらか、もしくは両方を上書きする必要がある。

.has_permission(self, request, view)
.has_object_permission(self, request, view, obj)

The methods should return True if the request should be granted access, and False otherwise.
# この2つのメソッドは、権限のあるアカウントからのアクセス(のrequest)の場合は、Trueが返されて、そうでない場合はFalseを返す。

If you need to test if a request is a read operation or a write operation, you should check the request method against the constant SAFE_METHODS, which is a tuple containing 'GET', 'OPTIONS' and 'HEAD'. For example:
# requestが読み込みか書き込みかをテストする必要がある場合は、GET OPTIONS HEADを含む既定の'SAFE_METHODS'を使って、さらに細かく分岐を行いチェックすることができる。例えば以下のような感じ

if request.method in permissions.SAFE_METHODS:
    # Check permissions for read-only request
else:
    # Check permissions for write request

Note: The instance-level has_object_permission method will only be called if the view-level has_permission checks have already passed. Also note that in order for the instance-level checks to run, the view code should explicitly call .check_object_permissions(request, obj). If you are using the generic views then this will be handled for you by default.
# has_object_permissionメソッドの方は、has_permissionをpassした時だけ呼び出される。
# the instance-levelのchecksをするためには、view codeは、.check_object_permissions(request, obj)を呼び出す必要がある。
# もしgeneric viewsを使ってたら、デフォルトでハンドルされるよ。

うーん、翻訳してもよくわからんw