How to use different Django Rest Framework serializers for the same query in Generic Views

I am using the Django Rest Framework in an API project and trying to figure out if there is a way to use two different serializers with common views (e.g. CreateAPIView). I want to use one serializer to deserialize a POST request and another to serialize the received response.

Here is what I am trying to do; I will illustrate the use of album / track examples from documents:

The model I'm working with has a ForeignKey relationship. In the API, I would just like to include FK in the request when assigning the relationship, so in the serializer I use PrimaryKeyRelatedField, just like the AlbumSerializer processes the relation to the tracks:

class CreateAlbumSerializer(serializers.ModelSerializer): tracks = serializers.PrimaryKeyRelatedField(many=True) class Meta: model = Album fields = ('album_name', 'artist', 'tracks') 

However, in response, I would like to include a full view of the album using ModelSerializer, not just PK, slug, etc., something like this:

 class AlbumSerializer(serializers.ModelSerializer): tracks = TrackSerializer(many=True, read_only=True) class Meta: model = Album fields = ('album_name', 'artist', 'tracks') class TrackSerializer(serializers.ModelSerializer): class Meta: model = Album fields = ('order', 'title', 'duration') 

General DRF views allow you to either specify serializer_class or override the get_serializer_class method, but I cannot figure out how to use this to accomplish what I need.

Is there something obvious that I'm missing? It seems like a reasonable thing to do, but I can't figure out how to do it.

+5
source share
1 answer

Approach No. 1

Overwrite shared mixes in DRF ViewSet . For instance:

 class MyViewSet(CreateModelMixin, MultipleSerializersViewMixin, ViewSet): serializer_class = CreateAlbumSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) saved = self.perform_create(serializer) serializer = self.get_serializer(instance=saved, serializer_class=AlbumSerializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): return serializer.save() 

MultipleSerializersViewMixin is taken from django-rest-framework-braces .

Approach No. 2

Configure to_representation for CreateAlbumSerializer . For instance:

 class MyViewSet(CreateModelMixin, ViewSet): serializer_class = CreateAlbumSerializer class CreateAlbumSerializer(serializers.ModelSerializer): tracks = serializers.PrimaryKeyRelatedField(many=True) class Meta: model = Album fields = ('album_name', 'artist', 'tracks') def to_representation(self, instance): data = super(CreateAlbumSerializer, self).to_representation(instance) data['tracks'] = TrackSerializer(instance=instance.tracks).data return data 

Comparison

I personally like the approach # 1 instead of # 2, although it is more detailed, since it does not leak any of the custom creation / response logic for serializers. I think that the serializer should just know how to serialize, and all user requirements for choosing different serializers for the job should be done in the views.

+5
source

All Articles