Change a field in a Django REST Framework ModelSerializer based on the request type?
There is a feature of DRF where you can dynamically change the fields on the serializer http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields
My use case: use slug field on GET so we can see nice rep of a relation, but on POST/PUT switch back to the classic primary key update. Adjust your serializer to something like this:
class FooSerializer(serializers.ModelSerializer):
bar = serializers.SlugRelatedField(slug_field='baz', queryset=models.Bar.objects.all())
class Meta:
model = models.Foo
fields = '__all__'
def __init__(self, *args, **kwargs):
super(FooSerializer, self).__init__(*args, **kwargs)
try:
if self.context['request'].method in ['POST', 'PUT']:
self.fields['bar'] = serializers.PrimaryKeyRelatedField(queryset=models.Bar.objects.all())
except KeyError:
pass
The KeyError is sometimes thrown on code initialisation without a request, possibly unit tests.
Enjoy and use responsibly.
IMHO, multiple serializers are only going to create more and more confusion.
Rather I would prefer below solution:
- Don't change your viewset (leave it default)
- Add .validate() method in your serializer; along with other required .create or .update() etc. Here, real logic will go in validate() method. Where based on request type we will be creating validated_data dict as required by our serializer.
I think this is the cleanest approach.
See my similar problem and solution at DRF: Allow all fields in GET request but restrict POST to just one field
You are looking for the get_serializer_class
method on the ViewSet
. This allows you to switch on request type for which serializer that you want to use.
from rest_framework import viewsets
class MyModelViewSet(viewsets.ModelViewSet):
model = MyModel
queryset = MyModel.objects.all()
def get_serializer_class(self):
if self.action in ('create', 'update', 'partial_update'):
return MySerializerWithPrimaryKeysForCreatingOrUpdating
else:
return MySerializerWithNestedData