Home > Net >  How to update PrimaryKeyRelatedField field of a nested relation? / Allow to GET a full object but PO
How to update PrimaryKeyRelatedField field of a nested relation? / Allow to GET a full object but PO

Time:08-25

In the serializer, country is the object of Country Model, and I have added a PrimaryKeyRelatedField with ending *_id to get the id and use it to send from the front-end if there is any change.

The Address Serializer:

class AddressSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    country = CountrySerializer(read_only = True)
    country_id = serializers.PrimaryKeyRelatedField(queryset = Country.objects.all(), source="country") #field added to get the id

    class Meta:
        model = Address
        fields = '__all__'

class CompanySerializer(serializers.ModelSerializer):
    category = CategorySerializer(read_only=True)
    category_id = serializers.PrimaryKeyRelatedField(queryset = Category.objects.all(), source='category', allow_null=True)
    addresses = AddressSerializer(many=True, read_only=False)

    class Meta:
        model = Company
        fields = '__all__'

    def update(self, instance, validated_data):
        addresses = validated_data.pop('addresses')
        instance = super().update(instance, validated_data)

        address_list = []
        for address in addresses:
            address_id = address['id']
            if address_id != 0:
                address_instance = Address.objects.get(id = address_id)
                address_instance.country_id = address['country_id']
                address_instance.save()
            elif address_id == 0:
                address.pop('id', None)
                
        address_list.append(Address.objects.create(**address))
           instance.addresses.add(*address_list)
           return instance

JSON Request TO UPDATE Company and addresses

{
   "id":25,
   "category_id":1,
   "name":"COMPANY SA DE CV",
   "addresses":[{
         "id":1,
         "country_id":2,
         "content_type":36,
         "object_id":25 
   }]
}

My problem is that, if I send (PATCH or PUT) in the request country_id or the others PrimaryKeyRelatedField, I receive the ERROR, since they don't appear in validated_data. I have tried with read_only=False, write_only=True in this field.

    ...
    File "/Users/obedramales/Sites/webegin-project/webegin/app/serializers.py", line 214, in update
    address_instance.country_id = address['country_id']
KeyError: 'country_id'

This is when it was updated from the company, but if I update just the address directly it does fine.

I would like to know what is the correct way to handle this please?

The models are defined like these:

class Company(SafeDeleteModel):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
    code = models.CharField(max_length=10, null=True)
    name = models.CharField(max_length=100)
    addresses = GenericRelation('Address')

In this model I have a generic relationship from Address to Company. A company can have many addresses.

class Address(SafeDeleteModel):
    content_type = models.ForeignKey(ContentType, related_name='model_addresses', on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey('content_type', 'object_id')
    country = models.ForeignKey(Country, on_delete=models.CASCADE, null=True, blank=True)

CodePudding user response:

I think you need to set the country_id field in the AddressSerializer.

class AddressSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField()
    country = CountrySerializer(read_only = True)
    country_id = serializers.PrimaryKeyRelatedField(queryset = Country.objects.all(), source="country") #field added to get the id

    class Meta:
        model = Address
        fields = '__all__'
        extra_fields = ['country_id']

The country_id field is not defined in the Address class. So you need to set that field additionally.

CodePudding user response:

I tried changing the following line of code

address_instance.country_id = address['country_id']

to

address_instance.country = address['country']

and it works, When I send country_id updates the correct id, but it is necessary to have country_id declared

country = CountrySerializer(read_only = True)
country_id = serializers.PrimaryKeyRelatedField(source="country", queryset = Country.objects.all())

in JSON Request

...
"country_id": 3,
...
  • Related