user1544500 user1544500 - 3 years ago 155
reST (reStructuredText) Question

Django Rest Framework model Id field in nested relationship serializer

I'm usign Django Rest Framework where I have the following two serializers:

class ServiceSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()

class Meta:
model = ServiceType
fields = ('id', 'serviceName', 'servicePrice')


class CompanyShortListSerializer(serializers.ModelSerializer):

services = ServiceSerializer(many=True)

class Meta:
model = Company
fields = ( 'id','name','address','cost_per_patient','cost_per_month','renting_fee','services')


The ServiceType model looks like this:

class ServiceType(models.Model):
serviceName = EncryptedCharField(max_length=100, blank=True, verbose_name = "Typ usługi")
servicePrice = EncryptedFloatField(null=True, blank=True, verbose_name = "Cena usługi", validators = [MinValueValidator(0.1), MaxValueValidator(999)])
company = models.ForeignKey(Company, related_name = 'services')


I would like to update the existing instances by changing the related services (e.g. deleting some of them). To achieve this I'm doing this:

def update(self, instance, validated_data):
# Updates an exisitng Company with several services
instance.name = validated_data['name']
instance.address = validated_data['address']
instance.cost_per_patient = validated_data['cost_per_patient']
instance.renting_fee = validated_data['renting_fee']
services_data = validated_data['services']

for item in services_data:
updatedService = ServiceType(
serviceName = item['serviceName'],
servicePrice = item['servicePrice'],
id=item['id'],
company=instance)
updatedService.save()

return instance


The problem that I'm facing is that the
service['id']
field is not provided - which means I get a
KeyError 'id'
- although I added it explicitly in the
ServiceSerializer
id
field.

EDIT

Here's an exemplary request (taken from Chrome) that I'm posting:

{ "id":49,"name":"Test 1",
"address":"Testowa 1",
"renting_fee":200,
"cost_per_month":300,
"cost_per_patient":null,
"services":[
{"id":67,"serviceName":"Terapia","servicePrice":100},
{"id":68,"serviceName":"Terapia par","servicePrice":150},
{"id":69,"serviceName":"Terapia po angielsku","servicePrice":120}
]
}


What am I doing wrong and how to get the ID of a an object(basically ServiceSerializer) using nested serializers?

EDIT no.2

When I print from the serializer update function I get the following:

print(self.data['services'])
gives me:

[
OrderedDict([('id', 67), ('serviceName', u'Terapia'), ('servicePrice', 100.0)]),
OrderedDict([('id', 68), ('serviceName', u'Terapia par'), ('servicePrice', 150.0)]),
OrderedDict([('id', 69), ('serviceName', u'Terapia po angielsku'), ('servicePrice', 120.0)]),
OrderedDict([('id', 70), ('serviceName', u'Terapia grupowa'), ('servicePrice', 140.0)])
]


However,
print(services_data)
gives the following (basically the same, but without the id):

[
OrderedDict([(u'serviceName', u'Terapia'), (u'servicePrice', 100.0)]),
OrderedDict([(u'serviceName', u'Terapia par'), (u'servicePrice', 150.0)]),
OrderedDict([(u'serviceName', u'Terapia po angielsku'), (u'servicePrice', 120.0)])
]


And the
ids
get lost ...

EDIT no.3

According to the Django Rest Framework docs If certain field will be shall be in the serializer output representation it should be a
HiddenField
. This however requires a
default
value ... I have checked that and indeed using this HiddenField with a default value 'solves' the problem - the ID is there in validated_data. The problem is that the
id
is not correct. Is there a possibility to set this
id
to the value of the object sent to the serializer?

Answer Source

Ok - I think I found the answer after ... carefully reading the docs :)

So according to the docs the id field could be set to a ModelField like this:

id = serializers.ModelField(model_field=ServiceType()._meta.get_field('id'))

Indeed, after adding this line the id field is present in validated_data :)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download