所以我有个这样的模特。
class Member(BaseModel):
objects = models.Manager()
user = models.ForeignKey('api_backend.User', db_index=True, on_delete=models.CASCADE)
cluster = models.ForeignKey('api_backend.Cluster', on_delete=models.CASCADE)
以及相同的通用api视图。
lass MemberPutRetrieveUpdateDeleteView(PutAsCreateMixin, MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView):
queryset = api_models.Member.objects.all()
permission_classes = [permissions.IsAuthenticated, IsMemberOrKickMembers]
lookup_fields = ['user', 'cluster']
def get_serializer_class(self):
if self.request.method in ['PUT']:
return api_serializers.PartialMemberSerializer
return api_serializers.MemberSerializer
def destroy(self, request, *args, **kwargs):
member = self.get_object()
if member.cluster.owner == member.user:
raise exceptions.ValidationError("cannot delete membership with this cluster as you own it.")
return super(MemberPutRetrieveUpdateDeleteView, self).destroy(request, *args, **kwargs)
我目前正在使用这些混合器。
class PutAsCreateMixin(object):
"""
The following mixin class may be used in order to support PUT-as-create
behavior for incoming requests.
"""
def update(self, request, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object_or_none()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
if instance is None:
if not self.lookup_fields:
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
lookup_value = self.kwargs[lookup_url_kwarg]
extra_kwargs = {self.lookup_field: lookup_value}
else:
# add kwargs for additional fields
extra_kwargs = {field: self.kwargs[field] for field in self.lookup_fields if self.kwargs[field]}
serializer.save(**extra_kwargs)
return Response(serializer.data, status=201)
serializer.save()
return Response(serializer.data)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
def get_object_or_none(self):
try:
return self.get_object()
except Http404:
if self.request.method == 'PUT':
# For PUT-as-create operation, we need to ensure that we have
# relevant permissions, as if this was a POST request. This
# will either raise a PermissionDenied exception, or simply
# return None.
self.check_permissions(clone_request(self.request, 'POST'))
else:
# PATCH requests where the object does not exist should still
# return a 404 response.
raise
class MultipleFieldLookupMixin(object):
"""
Apply this mixin to any view or viewset to get multiple field filtering
based on a `lookup_fields` attribute, instead of the default single field filtering.
"""
def get_object(self):
queryset = self.get_queryset() # Get the base queryset
queryset = self.filter_queryset(queryset) # Apply any filter backends
filter = {}
for field in self.lookup_fields:
if self.kwargs[field]: # Ignore empty fields.
filter[field] = self.kwargs[field]
obj = get_object_or_404(queryset, **filter) # Lookup the object
self.check_object_permissions(self.request, obj)
return obj
因此,在我的序列化程序中,我有多个查找字段- -user
和cluster
。这两个都是外键,在url中都有自己的kwargs。
所以我的api url是这样的。
path('clusters/<int:cluster>/members/<int:user>/', views.MemberPutRetrieveUpdateDeleteView.as_view())
我希望一个样本url是这样的:
'clusters/3/members/2/'
其中1是集群的id,2是成员的id。因此,基本上,对这个url的put请求必须创建一个成员,该成员具有:
的集群外键
但是,当试图创建相同的混音时,我会得到以下错误。
in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "2": "Member.user" must be a "User" instance.
如何纠正此错误?有人能帮帮我吗?非常感谢!
发布于 2021-01-08 19:51:42
答案其实很简单,我希望这能节省很多时间。
我必须将查找字段更改为
lookup_fields = ['user_id', 'cluster_id']
和url kwargs到以下
'clusters/<int:cluster_id>/members/<int:user_id>/'
这样,django就知道url中只有外键的id,而不是外键对象本身。当使用查找字段执行-创建时,一切都像预期的那样工作!
https://stackoverflow.com/questions/65626527
复制相似问题