[Solved]-How to update values in instance when have a custom .update() to update many-to-many relations in DRF writable nested serializer

1πŸ‘

βœ…

I was able to track down the issue in this case. I was using .prefetch_related() on queryset which is causing instance to use prefetched data for many to many relations. I have got two solution which may cause a few more database hits to fetch updated data.

1. Not using .prefetch_related()

One obvious way is not to use .prefetch_related() Which is not recommended as it will result into high number of DB hits.

OR

2. Fetching updated model instance after updating many-to-many relations in update method of serializer

instance = self.context['view'].get_queryset().get(
    id=instance.id
)

Modified .update() of TeamSerializer

@transaction.atomic
def update(self, instance, validated_data):
    '''
    Cutomize the update function for the serializer to update the
    related_field values.
    '''

    if 'memberships' in validated_data:
        instance = self._update_membership(instance, validated_data)

        # remove memberships key from validated_data to use update method of
        # base serializer class to update model fields
        validated_data.pop('memberships', None)

        # fetch updated model instance after updating many-to-many relations
        instance = self.context['view'].get_queryset().get(
            id=instance.id
        )
    return super(TeamSerializer, self).update(instance, validated_data)

If someone have better approach I would appreciate if they can add an answer to this question.

πŸ‘€Manjit Kumar

4πŸ‘

I think you have to β€œreload” the players field with instance.players.all(), because it the queryset is already evaluated in the is_valid method of the serializer.

@transaction.atomic
def update(self, instance, validated_data):
    '''
    Cutomize the update function for the serializer to update the
    related_field values.
    '''

    if 'memberships' in validated_data:
        instance = self._update_membership(instance, validated_data)

        # remove memberships key from validated_data to use update method of
        # base serializer class to update model fields
        validated_data.pop('memberships', None)
        instance.players.all()

    return super(TeamSerializer, self).update(instance, validated_data)
πŸ‘€ilse2005

Leave a comment