Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework, use different serializers in the same ModelViewSet

I would like to provide two different serializers and yet be able to benefit from all the facilities of ModelViewSet:

  • When viewing a list of objects, I would like each object to have an url which redirects to its details and every other relation appear using __unicode __ of the target model;

example:

{   "url": "http://127.0.0.1:8000/database/gruppi/2/",   "nome": "universitari",   "descrizione": "unitn!",   "creatore": "emilio",   "accesso": "CHI",   "membri": [     "emilio",     "michele",     "luisa",     "ivan",     "saverio"   ] } 
  • When viewing the details of an object, I would like to use the default HyperlinkedModelSerializer

example:

{   "url": "http://127.0.0.1:8000/database/gruppi/2/",   "nome": "universitari",   "descrizione": "unitn!",   "creatore": "http://127.0.0.1:8000/database/utenti/3/",   "accesso": "CHI",   "membri": [     "http://127.0.0.1:8000/database/utenti/3/",     "http://127.0.0.1:8000/database/utenti/4/",     "http://127.0.0.1:8000/database/utenti/5/",     "http://127.0.0.1:8000/database/utenti/6/",     "http://127.0.0.1:8000/database/utenti/7/"   ] } 

I managed to make all this work as I wish in the following way:

serializers.py

# serializer to use when showing a list class ListaGruppi(serializers.HyperlinkedModelSerializer):     membri = serializers.RelatedField(many = True)     creatore = serializers.RelatedField(many = False)      class Meta:         model = models.Gruppi  # serializer to use when showing the details class DettaglioGruppi(serializers.HyperlinkedModelSerializer):     class Meta:         model = models.Gruppi 

views.py

class DualSerializerViewSet(viewsets.ModelViewSet):     """     ViewSet providing different serializers for list and detail views.      Use list_serializer and detail_serializer to provide them     """     def list(self, *args, **kwargs):         self.serializer_class = self.list_serializer         return viewsets.ModelViewSet.list(self, *args, **kwargs)      def retrieve(self, *args, **kwargs):         self.serializer_class = self.detail_serializer         return viewsets.ModelViewSet.retrieve(self, *args, **kwargs)  class GruppiViewSet(DualSerializerViewSet):     model = models.Gruppi     list_serializer = serializers.ListaGruppi     detail_serializer = serializers.DettaglioGruppi      # etc. 

Basically I detect when the user is requesting a list view or a detailed view and change serializer_class to suit my needs. I am not really satisfied with this code though, it looks like a dirty hack and, most importantly, what if two users request a list and a detail at the same moment?

Is there a better way to achieve this using ModelViewSets or do I have to fall back using GenericAPIView?

EDIT:
Here's how to do it using a custom base ModelViewSet:

class MultiSerializerViewSet(viewsets.ModelViewSet):     serializers = {          'default': None,     }      def get_serializer_class(self):             return self.serializers.get(self.action,                         self.serializers['default'])  class GruppiViewSet(MultiSerializerViewSet):     model = models.Gruppi      serializers = {         'list':    serializers.ListaGruppi,         'detail':  serializers.DettaglioGruppi,         # etc.     } 
like image 200
BlackBear Avatar asked Mar 24 '14 17:03

BlackBear


People also ask

Do we need Serializers in Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

Should either include a Serializer_class attribute or override the?

serializer_class - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the get_serializer_class() method.

What is difference between APIView and Viewset?

APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.


1 Answers

Override your get_serializer_class method. This method is used in your model mixins to retrieve the proper Serializer class.

Note that there is also a get_serializer method which returns an instance of the correct Serializer

class DualSerializerViewSet(viewsets.ModelViewSet):     def get_serializer_class(self):         if self.action == 'list':             return serializers.ListaGruppi         if self.action == 'retrieve':             return serializers.DettaglioGruppi         return serializers.Default # I dont' know what you want for create/destroy/update.                 
like image 137
user133688 Avatar answered Sep 19 '22 05:09

user133688