从 Django REST 框架教程实现自定义权限
Implementing the custom permissions from the Django REST framework tutorial
我正在关注 Django REST framework tutorial (part 4),但我观察到 API 的行为与教程中的预期行为之间存在差异。这是我的项目级别 urls.py
:
from django.contrib import admin
from django.urls import path, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
path('', include('snippets.urls'))
]
urlpatterns += [
path('api-auth/', include('rest_framework.urls'))
]
这是随附的 snippets.urls
:
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('snippets/', views.SnippetList.as_view()),
path('snippets/<int:pk>/', views.SnippetDetail.as_view())
]
urlpatterns = format_suffix_patterns(urlpatterns)
我创建了一个具有自定义权限的 permissions.py
class IsOwnerOrReadOnly
:
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
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
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
并且我已将此 class 添加到 SnippetDetail
中的 permission_classes
views.py
中的 class:
from django.contrib.auth.models import User
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from rest_framework import generics, permissions
from snippets.permissions import IsOwnerOrReadOnly
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)
但是,当我发出 POST 请求时仅指定我的凭据(使用 Httpie),我收到 400 错误请求:
Kurts-MacBook-Pro:~ kurtpeek$ http -a kurtpeek:mypassword POST http://localhost:8000/snippets/ code="print 789"
HTTP/1.1 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 37
Content-Type: application/json
Date: Wed, 24 Jan 2018 18:13:47 GMT
Server: WSGIServer/0.2 CPython/3.6.4
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
"owner": [
"This field is required."
]
}
显然,我需要指定 owner="1"
才能让它工作:
Kurts-MacBook-Pro:~ kurtpeek$ http -a kurtpeek:mypassword POST http://localhost:8000/snippets/ code="print 789" owner="1"
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 103
Content-Type: application/json
Date: Wed, 24 Jan 2018 18:13:35 GMT
Server: WSGIServer/0.2 CPython/3.6.4
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
"code": "print 789",
"id": 3,
"language": "python",
"linenos": false,
"owner": 1,
"style": "friendly",
"title": ""
}
但是,据我了解IsOwnerOrReadOnly
权限class的has_object_permission
方法的逻辑,所有者应该是从request.user
推断出来的。这也不是本教程中给出示例的方式。谁能看出这里出了什么问题?
这与您的序列化程序的方式有关defined/used,这不是权限问题。字段 'owner' 需要在序列化程序中设置为只读或不需要。
POST 请求应该转到您的 SnippetList
视图,而不是 SnippetDetail
,因此不使用自定义权限 class。
虽然我不知道你为什么会收到这个错误。 According to the tutorial,您应该将 owner
设置为 SnippetSerializer
中的只读字段。
owner = serializers.ReadOnlyField(source='owner.username')
我正在关注 Django REST framework tutorial (part 4),但我观察到 API 的行为与教程中的预期行为之间存在差异。这是我的项目级别 urls.py
:
from django.contrib import admin
from django.urls import path, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),
path('', include('snippets.urls'))
]
urlpatterns += [
path('api-auth/', include('rest_framework.urls'))
]
这是随附的 snippets.urls
:
from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
path('snippets/', views.SnippetList.as_view()),
path('snippets/<int:pk>/', views.SnippetDetail.as_view())
]
urlpatterns = format_suffix_patterns(urlpatterns)
我创建了一个具有自定义权限的 permissions.py
class IsOwnerOrReadOnly
:
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
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
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
并且我已将此 class 添加到 SnippetDetail
中的 permission_classes
views.py
中的 class:
from django.contrib.auth.models import User
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from rest_framework import generics, permissions
from snippets.permissions import IsOwnerOrReadOnly
class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)
但是,当我发出 POST 请求时仅指定我的凭据(使用 Httpie),我收到 400 错误请求:
Kurts-MacBook-Pro:~ kurtpeek$ http -a kurtpeek:mypassword POST http://localhost:8000/snippets/ code="print 789"
HTTP/1.1 400 Bad Request
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 37
Content-Type: application/json
Date: Wed, 24 Jan 2018 18:13:47 GMT
Server: WSGIServer/0.2 CPython/3.6.4
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
"owner": [
"This field is required."
]
}
显然,我需要指定 owner="1"
才能让它工作:
Kurts-MacBook-Pro:~ kurtpeek$ http -a kurtpeek:mypassword POST http://localhost:8000/snippets/ code="print 789" owner="1"
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 103
Content-Type: application/json
Date: Wed, 24 Jan 2018 18:13:35 GMT
Server: WSGIServer/0.2 CPython/3.6.4
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN
{
"code": "print 789",
"id": 3,
"language": "python",
"linenos": false,
"owner": 1,
"style": "friendly",
"title": ""
}
但是,据我了解IsOwnerOrReadOnly
权限class的has_object_permission
方法的逻辑,所有者应该是从request.user
推断出来的。这也不是本教程中给出示例的方式。谁能看出这里出了什么问题?
这与您的序列化程序的方式有关defined/used,这不是权限问题。字段 'owner' 需要在序列化程序中设置为只读或不需要。
POST 请求应该转到您的 SnippetList
视图,而不是 SnippetDetail
,因此不使用自定义权限 class。
虽然我不知道你为什么会收到这个错误。 According to the tutorial,您应该将 owner
设置为 SnippetSerializer
中的只读字段。
owner = serializers.ReadOnlyField(source='owner.username')