ves*_*sii 5 python django django-rest-framework
我想构建一个 REST API,用户可以根据其权限对对象进行操作。考虑代表一辆汽车的记录 - 它包含许可证号、汽车类型和额外信息。还要考虑以下用户系统:
car
对象。可以修改也可以删除。每条记录可以包含多个所有者/编辑者/查看者(创建对象的用户应自动成为所有者)。此外,所有者可以添加或删除编辑者/查看者。在我的脑海中,我将其视为所有者/编辑/观众的列表。
因此,在 GET 请求的情况下,我希望能够返回用户有权访问的所有对象,分为这三个类别。
所以在我的api
应用程序下,我有以下代码:
该models.py
文件包含:
class CarRecord(models.Model):
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
Run Code Online (Sandbox Code Playgroud)
该serializers.py
文件包含:
class CarRecordSerializer(serializers.ModelSerializer):
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
class Meta:
model = CarRecord
fields = ('__all__')
Run Code Online (Sandbox Code Playgroud)
在view.py
我有:
class CarRecordViews(APIView):
def get(self, request):
if not request.user.is_authenticated:
user = authenticate(username=request.data.username, password=request.data.password)
if user is not None:
return Response(data={"error": "invalid username/password"}, status=status.HTTP_401_UNAUTHORIZED)
# return all records of cars that user some type of permission for
Run Code Online (Sandbox Code Playgroud)
现在,我想获取user
他有权查询的所有记录(及其权限类型)。我想在下面添加三个额外的字段CarRecord
- 每个字段都是包含该权限类型的用户列表。但我不确定这是否是“Django 方式”。所以想先咨询一下SO。
编辑:我尝试将以下字段添加到我的CarRecord
班级中:
owners = models.ManyToManyField(User, related_name='car_owners', verbose_name=('owners'), default=[])
Run Code Online (Sandbox Code Playgroud)
我还补充道:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username']
lass CarRecordSerializer(serializers.ModelSerializer):
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
owners = UserSerializer(many=True)
class Meta:
model = CarRecord
fields = ('__all__')
Run Code Online (Sandbox Code Playgroud)
我创建实例的方式CarRecordSerializer
是:
serializer = CarRecordSerializer(data=request.data)
Run Code Online (Sandbox Code Playgroud)
但我得到:
{
"error": {
"owners": [
"This field is required."
]
}
}
Run Code Online (Sandbox Code Playgroud)
如何让它发挥作用?我想我的问题是如何序列化 ManyToMany 对象?
EDIT2:我的第二次尝试是:
class CarRecord(models.Model):
date_created = models.DateTimeField()
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
owners = models.ManyToManyField(User, related_name='car_owners', verbose_name=('owners'), default=[]))
creator = models.ForeignKey(User,on_delete=models.DO_NOTHING)
# ...
class CarRecordSerializer(serializers.ModelSerializer):
date_created = serializers.DateTimeField(default=datetime.now(timezone.utc))
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
creator = serializers.StringRelatedField()
owners = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
class Meta:
model = CarRecord
fields = '__all__'
def create(self, validated_data):
self.owners = [self.context['creator']]
record = CarRecord(**validated_data, creator=self.context['creator'])
record.save()
return record
# ...
# In post method:
serializer = CarRecordSerializer(data=request.data, context={ 'creator': user })
Run Code Online (Sandbox Code Playgroud)
但现在,在 GET 方法中,我使用用户过滤所有者列表,但找不到对象:
> CarRecord.objects.filter(owners=user)
<QuerySet []>
Run Code Online (Sandbox Code Playgroud)
另外,在“管理”部分中,我看到所有对象自动将所有用户包含在列表中owners/editors/viewers
。这是为什么?所有者应仅包含创建记录的用户,编辑者和查看者应为空列表。在另一个查询中,所有者可以添加其他所有者/编辑者/查看者。
小智 1
这是我认为可能是正确的解决方案
class CarRecord(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=50)
license = models.CharField(max_length=50)
owners = models.ManyToManyField(User, related_name='car_owners')
creator = models.ForeignKey(User,on_delete=models.DO_NOTHING)
class CarRecordSerializer(serializers.ModelSerializer):
creator = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), required=False)
owners_details = UserSerializer(source='owners', many=True, read_only=True)
class Meta:
model = CarRecord
fields = '__all__'
def create(self, validated_data):
try:
new_owners = validated_data.pop('owners')
except:
new_owners = None
car_record = super().create(validated_data)
if new_owners:
for new_owner in new_owners:
car_record.owners.add(new_owner)
return car_record
Run Code Online (Sandbox Code Playgroud)
在views.py中
from rest_frameword import generics
from rest_framework import permissions
class CustomCarRecordPermissions(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method == 'GET':
return True
elif request.method == 'PUT' or request.method == 'PATCH':
return request.user == obj.creator or request.user in obj.owners.all()
elif request.method == 'DELETE':
return request.user == obj.creator
return False
class CarRecordListCreate(generics.ListCreateAPIView):
permission_classes = (IsAuthenticated, )
serializer_class = CarRecordSerializer
queryset = CarRecord.objects.all()
def post(self, request, *args, **kwargs):
request.data['creator'] = request.user.id
return super().create(request, *args, **kwargs)
class CarRecordDetailView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (CustomCarRecordPermissions, )
serializer_class = CarRecordSerializer
lookup_field = 'pk'
queryset = CarRecord.objects.all()
Run Code Online (Sandbox Code Playgroud)
模型是不言自明的;在CarRecord序列化器中,我们将创建者设置为必需的False和主键相关字段,以便我们可以在创建之前提供请求用户ID,如views.py post方法中所示。
在详细视图中,我们设置自定义权限;如果请求是 GET 我们允许权限。但如果请求是 PUT 或 PATCH,则允许所有者和创建者。但如果是删除请求,则仅允许创建者。
归档时间: |
|
查看次数: |
562 次 |
最近记录: |