Reputation: 309
I get a JSON response with data from multiple objects, run everything through the serializer and call serializer.save()
which creates new objects but doesnt update the existing ones.
view
data = JSONParser().parse(request)
serializer = CellCESaveSerializer(data=data, many = True, context = {'descriptoridlist' : descriptoridlist}, partial=True)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False)
the serializer
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.rstrip(",") # Needed because of JSON response
data = data.split(",") # Split string to list
data = [int(i) for i in data] # convert str to int
did = self.context['descriptoridlist']
x = (did,data) # Create Array
return super().to_internal_value(x)
class CellCESaveSerializer(serializers.ModelSerializer):
row = serializers.SlugRelatedField(slug_field="name",queryset=Descriptor.objects.all() ) # foreignkey mit namen
val = StringArrayField()
class Meta:
model = CellCE
fields = ('row','val')
How can i update the existing objects without creating new objects?
EDIT 1:
After adding @neverwalkaloner changes i realised i need to use ListSerializer to update multiple objects. I adjusted my code with help of the DRF documentation. (I changed the serializer to a ListSerializer, added the id Field and the update method.)
serializer:
class CellCESaveSerializer(serializers.ListSerializer):
row = serializers.SlugRelatedField(slug_field="name",queryset=Descriptor.objects.all()) # foreignkey mit namen
val = StringArrayField()
id = serializers.IntegerField()
class Meta:
model = CellCE
fields = ('row','val')
def update(self, instance, validated_data):
CellCE_mapping = {CellCE.id: CellCE for CellCE in instance}
data_mapping = {item['id']: item for item in validated_data}
# Perform creations and updates.
ret = []
for CellCE_id, data in data_mapping.items():
CellCE = CellCE_mapping.get(CellCE_id, None)
if CellCE is None:
ret.append(self.child.create(data))
else:
ret.append(self.child.update(CellCE, data))
# Perform deletions.
for CellCE_id, CellCE in CellCE_mapping.items():
if CellCE_id not in data_mapping:
CellCE.delete()
return ret
I get the error:
AssertionError: `child` is a required argument.
What am i missing?
Upvotes: 4
Views: 6350
Reputation: 105
No need to use ListSerializer because when you pass "many=True", it also use ListSerializer class. If you want to update once object, please include "id" field and pass its value in input data.
Upvotes: -1
Reputation: 47354
Serializer's save()
method check if serializer's self.instance
is empty or not. If self.instance
is empty save()
will call create()
method, otherwise it will call update()
method.
So to update instance with serializer, you need to pass as it's first argument updating object:
obj = CellCE.objects.get(id='some_id') # Object wich will be updated
serializer = CellCESaveSerializer(obj, data=data, many = True, context = {'descriptoridlist' : descriptoridlist}, partial=True)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False)
Upvotes: 2