Fix partial update for the ListSerializer. by NewVadim · Pull Request #4222 · encode/django-rest-framework (original) (raw)

This commit make the update from DRF 3.5.3 to 3.6.3 fail with:


  File "/lib/python3.5/site-packages/rest_framework/serials
    self._fields[key] = value
  File "/lib/python3.5/site-packages/rest_framework/utils/_
    field.bind(field_name=key, parent=self.serializer)
  File "/lib/python3.5/site-packages/rest_framework/seriald
    self.partial = self.parent.partial
AttributeError: 'YourSerializer' object has no attribute 'partial'

Cause is an entry in YourSerializer that nests another serializer:

class YourGroupSerializer(ModelValidatorMixin, SecureSerializerMixin, serializers.HyperlinkedModelSerializer):
    
    # Mostly used for SETTING
    your_set = YourSerializer(many=True, read_only=True)

Which then fails on the SecureSerializerMixin that filters nested entries on allowed entrys for that user:

class SecureSerializerMixin(object):
    """
    Filters the queryset for a related field to those items the user has permissions for.
    
    Does work with all serializers, but in general on nested serializers you don't use the queryset method, so then it does not work.
    
    IN THE SERIALIZER
    
    Without this mixin, the browsable api would show all options, not only those of the user.
    
    Also without this mixin, it would be possible to post (=create) a horse in another stable, etc.
    
    """
    def filter_queryset(self, field, kwargs):
        try: 

            request = kwargs['context']['request']
            # Not only for GET requests, but also for posts filter!
            if not kwargs['context'].get('do_not_filter_api', False):  # disables uneccesary filtering of serializers for performance
                self.fields.get(field).queryset = filter_queryset(request, self.fields.get(field).queryset)
            
            
        except AttributeError:
            pass
        except KeyError:

            # No context. For safety use empty queryset!
            try:
                self.fields.get(field).queryset = self.field.get(field).queryset.none()
            except AttributeError:
                pass

    def __init__(self, *args, **kwargs):

        for field in self.fields:
            self.filter_queryset(field, kwargs)

        
        super(SecureSerializerMixin, self).__init__(*args, **kwargs)

The SecureSerializerMixin fails on for field in self.fields.