Reputation: 1273
I want users to be able to update only one specific field. For example:
models.py
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100)
class Meta:
ordering = ('created',)
serializer.py
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
views.py
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
Once the Snippet
is created, the user should only be able to update title
field.
I know I can achieve that by something like this:
serializers.py
def update(self, instance, validated_data):
"""
Update and return an existing `Snippet` instance, given the validated data.
"""
instance.title = validated_data.get('title', instance.title)
instance.save()
return instance
In serializer class. But I want to know, is there a way that browsable API show only title
field in edit form? And also skip validation for fields that are not required?
Upvotes: 25
Views: 9430
Reputation: 3089
While @petkostas answer is correct, it doesn't give you a full picture of how to achieve it.
First, Create a new serializer; let's call it SnippetUpdateSerializer
Now, you may have custom serializer fields like serializers.MethodFieldSerializer
that you would have defined in SnipperSerializer
; which you may not want to write again in your new serializer. A good approach is to use inheritance.
Taking the example from the question
class SnippetUpdateSerializer(SnippetSerializer): #<- pay attention here
class Meta(SnippetSerializer.Meta): # <- pay attention here
SnippetSerializer.Meta.extra_kwargs.update({ # update the dictionary
'id': {'read_only': True},
'code': {'read_only': True}, # you can also use {write_only: True} if you want this to be write only
'lineos': {'read_only': True},
'language': {'read_only': True},
'style': {'read_only': True}
}) # you may completely override by just using extra_kwargs, instead of SnippetSerializer.Meta.extra_kwargs
Now in your SnippetUpdateView
, use the above serializer.
If you are using class based views then set serializer_class = SnippetUpdateSerializer
Another approach is to return bad request
, from your update view if the user requests contain read_only fields. (not recommended)
Upvotes: 0
Reputation: 7460
Django REST Framework provides the read_only
and write_only
attributes for controlling what is used for editing and what is not.
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
extra_kwargs = {
'id': {'read_only': True},
'code': {'read_only': True},
'lineos': {'read_only': True},
'language': {'read_only': True},
'style': {'read_only': True}
}
The above will return all the fields on read requests but only title will be writable. You can find more at the official documentation: http://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields
Upvotes: 13