Django Rest Framework: Disable field update after object is created

后端 未结 11 1340
独厮守ぢ
独厮守ぢ 2020-11-30 20:15

I\'m trying to make my User model RESTful via Django Rest Framework API calls, so that I can create users as well as update their profiles.

However, as I go through

相关标签:
11条回答
  • 2020-11-30 20:52

    Another method would be to add a validation method, but throw a validation error if the instance already exists and the value has changed:

    def validate_foo(self, value):                                     
        if self.instance and value != self.instance.foo:
            raise serializers.ValidationError("foo is immutable once set.")
        return value         
    

    In my case, I wanted a foreign key to never be updated:

    def validate_foo_id(self, value):                                     
        if self.instance and value.id != self.instance.foo_id:            
            raise serializers.ValidationError("foo_id is immutable once set.")
        return value         
    

    See also: Level-field validation in django rest framework 3.1 - access to the old value

    0 讨论(0)
  • 2020-11-30 20:52
    class UserUpdateSerializer(UserSerializer):
        class Meta(UserSerializer.Meta):
            fields = ('username', 'email')
    
    class UserViewSet(viewsets.ModelViewSet):
        def get_serializer_class(self):
            return UserUpdateSerializer if self.action == 'update' else super().get_serializer_class()
    

    djangorestframework==3.8.2

    0 讨论(0)
  • 2020-11-30 20:54

    It seems that you need different serializers for POST and PUT methods. In the serializer for PUT method you are able to just except the username field (or set the username field as read only).

    class UserViewSet(viewsets.ModelViewSet):
        """
        API endpoint that allows users to be viewed or edited.
        """
        serializer_class = UserSerializer
        model = User
    
        def get_serializer_class(self):
            serializer_class = self.serializer_class
    
            if self.request.method == 'PUT':
                serializer_class = SerializerWithoutUsernameField
    
            return serializer_class
    
        def get_permissions(self):
            if self.request.method == 'DELETE':
                return [IsAdminUser()]
            elif self.request.method == 'POST':
                return [AllowAny()]
            else:
                return [IsStaffOrTargetUser()]
    

    Check this question django-rest-framework: independent GET and PUT in same URL but different generics view

    0 讨论(0)
  • 2020-11-30 20:57

    Another option (DRF3 only)

    class MySerializer(serializers.ModelSerializer):
        ...
        def get_extra_kwargs(self):
            extra_kwargs = super(MySerializer, self).get_extra_kwargs()
            action = self.context['view'].action
    
            if action in ['create']:
                kwargs = extra_kwargs.get('ro_oncreate_field', {})
                kwargs['read_only'] = True
                extra_kwargs['ro_oncreate_field'] = kwargs
    
            elif action in ['update', 'partial_update']:
                kwargs = extra_kwargs.get('ro_onupdate_field', {})
                kwargs['read_only'] = True
                extra_kwargs['ro_onupdate_field'] = kwargs
    
            return extra_kwargs
    
    0 讨论(0)
  • 2020-11-30 21:00

    I used this approach:

    def get_serializer_class(self):
        if getattr(self, 'object', None) is None:
            return super(UserViewSet, self).get_serializer_class()
        else:
            return SerializerWithoutUsernameField
    
    0 讨论(0)
提交回复
热议问题