【发布时间】:2021-06-18 02:56:45
【问题描述】:
我对 django 非常陌生,目前正在尝试生成对 localhost:8000/stateapi/id 的 api 调用,其中 id 是 json 中单个“状态”对象的 id(如 1、2 等)。 它通过将用户名和密码传递给“get-token”端点,然后使用该令牌调用 stateapi 端点来使用令牌身份验证。
我主要遵循本教程https://scotch.io/tutorials/build-a-rest-api-with-django-a-test-driven-approach-part-2 并不断收到“详细信息”:“您无权执行此操作。”
这里是 CreateView 处理“localhost:8000/stateapi”端点和 DetailsView 处理 localhost:8000/stateapi/id 端点的视图。
class CreateView(generics.ListCreateAPIView):
queryset = State.objects.all()
serializer_class = StateSerializer
permission_classes = (permissions.IsAuthenticated,IsOwner)
def perform_create(self, serializer):
"""Save the post data when creating a new State."""
serializer.save(owner=self.request.user)
class DetailsView(generics.RetrieveUpdateDestroyAPIView):
"""This class handles the http GET, PUT and DELETE requests."""
queryset = State.objects.all()
serializer_class = StateSerializer
permission_classes = (permissions.IsAuthenticated,IsOwner)
我似乎无法弄清楚为什么经过身份验证的用户有权从 CreateView 访问信息,但不能从 DetailsView 访问信息。
这是权限代码:
class IsOwner(BasePermission):
"""Custom permission class to allow only bucketlist owners to edit them."""
def has_object_permission(self, request, view, obj):
# Our problem is that we do not have a owner property for the object
"""Return True if permission is granted to the bucketlist owner."""
return obj.owner == request.user
在测试调用 DetailsView 时会发生什么时,我发现调用 DetailsView 时 obj.owner 为“None”,并且每当调用 CreateView 时 obj.owner 正确等于 request.user,这将解释为什么经过身份验证的用户可以向没有 id 的端点发出 get 请求,而不能向有 id 的端点发出请求。
有没有关于我怎么做的建议:
- a) 确保 obj 具有正确的“所有者”属性(CreateView 正在执行但 DetailsView 未执行的操作)
- b) 以某种方式更改我的权限
- c) 其他我想不到的东西。
谢谢!
你能分享你的 State 模型和 StateSerializer – Iain Shelvington 6 月 18 日 3:26
状态模型:
from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from django.dispatch import receiver
# Create your models here.
# 1 is /, 2 is -, 3 is (, 4 is ), 5 is .
class State(models.Model):
STATE = models.CharField(max_length=30,blank=True,null=True)
Team_Contact = models.CharField(max_length=100,blank=True,null=True)
CONTACT_INFORMATION = models.TextField(blank=True,null=True)
LEGISLATION1EXECUTIVE_ORDER = models.TextField(blank=True,null=True)
TESTING = models.TextField(blank=True,null=True)
TESTING1DEPLOYMENT_REQUIREMENTS_3SELF_CERTIFICATION4 = models.TextField(blank=True,null=True)
PRE2EMPTION = models.TextField(blank=True,null=True)
owner = models.ForeignKey('auth.User', related_name='statelists', on_delete=models.CASCADE,blank=True,null=True)
OVERSIGHT_DEPARTMENT = models.TextField(blank=True,null=True)
INFRASTRUCTURE_DEVELOPMENTS = models.TextField(blank=True,null=True)
CRASHES1SAFETY_INCIDENTS = models.TextField(blank=True,null=True)
DATA1PRIVACY_CONCERNS = models.TextField(blank=True,null=True)
PUBLIC_EDUCATION_FOR_AVS = models.TextField(blank=True,null=True)
LIABILITY1INSURANCE_REQUIREMENTS = models.TextField(blank=True,null=True)
HEALTH1EQUITY_CONCERNS = models.TextField(blank=True,null=True)
MISC5 = models.TextField(blank=True,null=True)
def __str__(self):
"""Return a human readable representation of the model instance."""
return "{}".format(self.STATE)
# This receiver handles token creation immediately a new user is created.
@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
序列化器:
from rest_framework import serializers
from .models import State
from django.contrib.auth.models import User
class StateSerializer(serializers.ModelSerializer):
"""Serializer to map the Model instance into JSON format."""
# understand exactly what this line does
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
"""Meta class to map serializer's fields with the model fields."""
model = State
fields = ('id','STATE','Team_Contact','CONTACT_INFORMATION','LEGISLATION1EXECUTIVE_ORDER','TESTING',
'TESTING1DEPLOYMENT_REQUIREMENTS_3SELF_CERTIFICATION4','PRE2EMPTION','OVERSIGHT_DEPARTMENT','INFRASTRUCTURE_DEVELOPMENTS',
'CRASHES1SAFETY_INCIDENTS','DATA1PRIVACY_CONCERNS','PUBLIC_EDUCATION_FOR_AVS','LIABILITY1INSURANCE_REQUIREMENTS',
'HEALTH1EQUITY_CONCERNS','MISC5', 'owner')
read_only_fields = ('STATE', 'Team_Contact','CONTACT_INFORMATION')
class UserSerializer(serializers.ModelSerializer):
"""A user serializer to aid in authentication and authorization."""
states = serializers.PrimaryKeyRelatedField(
many=True, queryset=State.objects.all())
class Meta:
"""Map this serializer to the default django user model."""
model = User
fields = ('id', 'username', 'states')
【问题讨论】:
-
你能分享你的
State模型和StateSerializer -
当然!我会分享它
-
这可能是因为所有者的序列化程序有
source=owner.username不确定这是必要的。我想这是一个字符串,而不是您期望的用户名对象。 -
我删除了它,但 stateapi/1 的权限仍然被拒绝 :(
标签: python django api django-rest-framework