Django Rest Framework model Id field in nested relationship serializer

时间:2016-04-07 10:42:54

标签: python django rest django-rest-framework

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?

4 个答案:

答案 0 :(得分:20)

好的 - 我想我找到了答案......仔细阅读the docs :)

因此,根据the docsid字段可以设置为这样的ModelField:

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

确实,在添加此行后,id字段出现在validated_data :)

答案 1 :(得分:11)

接受的答案有效但却不必要地复杂化。您只需将ID字段更改为不只读即可。例如。这样的事情会做:

id = serializers.IntegerField(required=False)

答案 2 :(得分:2)

您已将id设为ReadOnlyField。这就是id没有出现在验证数据中的原因。只需删除此行:

id = serializers.ReadOnlyField()

答案 3 :(得分:0)

更直接的选项:

id = serializers.IntegerField(write_only=False)