Louis Dhanis
Louis Dhanis

Reputation: 5

Updating nested PrimaryKeyRelatedField in Django Rest Framework

I'm trying to create an update function for one of my serializers which represents a Company where some people (user of my app) are admin. However when I make my request with Postman to update my Company object, it seems that my serializer does not get all the data i PUT in my API.

I have tried to use the full user object serializer in my Company serializer but in this case i must specify data I don't need and it does not even work.

When i PUT the name of my company like so:

{
    "id": 1,
    "admins": [
        5,
        6,
        7,
        9,
        11
    ],
    "name": "Mon entreprise"
}

My api responds this (the users with IDs 6 and 11 were added using the admin panel):

{
    "name": "Mon entreprise",
    "logo": "http://localhost:8000/api/companies/1/mwe.jpg",
    "admins": [
        6,
        11
    ]
}

I tried this to see what data were passed through the API

    def update(self, instance, validated_data):
        print (validated_data)

and the output was:

{'name': "Mon entreprise"}

My serializer:

class CompanySerializer(serializers.ModelSerializer):
    admins      = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

    class Meta:
        model = Company
        fields = ('name', 'logo', 'admins',)

    def update(self, instance, validated_data):
        print (validated_data)
        instance.logo = validated_data.get('logo', instance.logo)
        instance.name = validated_data.get('name', instance.name)
        instance.save()
        admin_list = validated_data.get('admins')
        print (admin_list)



        return instance

my model:

class Company(models.Model):
    admins          = models.ManyToManyField(User, related_name='admins')
    logo            = models.ImageField(blank=True)
    name            = models.CharField(max_length=200)

I don't understand why I only have {'name': "Mon entreprise"} as I added an admins field in my json for the PUT request

Upvotes: 0

Views: 1422

Answers (1)

ivissani
ivissani

Reputation: 2664

I've had the very same problem. It seems that PrimaryKeyRelatedField does not work properly with many=True for writing. In my team we have come up with the following temporary solution until we have time to dig more into why this does not work as expected:

class PrimaryKeyRelatedListField(serializers.ListField):
    def __init__(self, queryset=None, **kwargs):
        assert queryset is not None, 'queryset must be specified for PrimaryKeyRelatedListField'
        self.child = serializers.PrimaryKeyRelatedField(queryset=queryset)
        super().__init__(**kwargs)

    def get_value(self, dictionary):
        dictionary = dictionary.copy()

        keys = []
        for k, _ in dictionary.items():
            if k.startswith(f'{self.field_name}['):
                keys.append(k)
        for k in keys:
            dictionary.appendlist(self.field_name, dictionary.getlist(k)[0])

        return super().get_value(dictionary)

    def to_representation(self, data):
        return super().to_representation(data.all())

Hope this helps you.

Ok, so I've re read your question, and you have set read_only=True to your admins field, this will make DRF ignore whatever data you are sending... therefore these data will not reach the update() method of your serializer.

Upvotes: 2

Related Questions