I have a view that is used to update a field in my model. It’s represented as follows: stock_list = ArrayField(models.CharField())
Each value in the ArrayField is separated by commas.
I used a custom serializer method to allow for my backend to separate the elements in my PATCH obj
by commas.
serializers.py
:
class StringArrayField(ListField): """ String representation of an array field. """ def to_representation(self, obj): obj = super().to_representation(obj) # convert list to string return ",".join([str(element) for element in obj]) def to_internal_value(self, data): data = data.split(",") # convert string to list return super().to_internal_value(self, data) class StockListSerializer(serializers.ModelSerializer): stock_list = StringArrayField() class Meta: model = Bucket fields = ("stock_list",)
Below is my view that I use, the URL’s are linked up correctly, however I’m setting up my view wrong:
view.py:
class EditBucketSymbols(generics.RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] serializer_class = StockListSerializer def get_queryset(self): return Bucket.objects.all() def get_object(self, queryset=None, **kwargs): item = self.kwargs.get('pk') return get_object_or_404(Bucket, pk=item) def patch(self, request, *args, **kwargs): item = BucketDetail.get_object(self) data = request.data item.stock_list = data.get("stock_list", item.stock_list) serializer = StockListSerializer(data=item.stock_list, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Here is the PATCH error I get:
{ "non_field_errors": [ "Invalid data. Expected a dictionary, but got str." ] }
I’m not sure why my view is expecting a dictionary, I only want the users to PATCH the arrayfield known as stock_list
with the data they input.
Appreciate any debugging assistance here to get my PATCH view working properly as expected.
Advertisement
Answer
First, you need to change the super()
method calling of to_internal_value(...)
method (you were not calling it correctly)
class StringArrayField(serializers.ListField): def to_representation(self, obj): obj = super().to_representation(obj) return ",".join([str(element) for element in obj]) def to_internal_value(self, data): data = data.split(",") return super().to_internal_value(data) # update here
and then, use the generics.RetrieveUpdateAPIView
“as-is”, because, you don’t need any alterations to the view (at-least the minimal case you have given in the OP)
So, your view will become,
class EditBucketSymbols(generics.RetrieveUpdateAPIView): permission_classes = [IsAuthenticated] serializer_class = StockListSerializer queryset = Bucket.objects.all()
This will let you update the data with ease and keep in mind that the DRF expect the data in the following format,
{ "stock_list":"this,is,patch,request,test" }