How to pass extra argument to get_serializer_class

How to pass extra argument to get_serializer_class

Problem Description:

I need to select a serializer based on the value of an object instance. How do I pass an additional argument to get_serializer_class to be able to do the validation there?

def get_serializer_class(self, extra_option):
        if extra_option:
            return ModelSerializer
        return ModelSerializer2
serializer = self.serializer_class(data=request.data, extra_option=smth_instance)

Error:

TypeError: Field.__init__() got an unexpected keyword argument 'extra_option'

If I make a custom class then serializer selection works… maybe this is legit workaround?

 def choose_serializer(self, product, data):
        if product.document.type == 1:
            return Serializer1(product, data=data)
        elif product.document.type == 2:
            return Serializer2(product, data=data)
serializer = self.choose_serializer(data=request.data, product=product)

Solution – 1

It’s much easier to check the action to decide what serializer to use. Ex.

def get_serializer_class(self):
  if self.action == "retrieve":
    return ModelOutputSerializer
  else:
    return ModelDefaultSerializer

Otherwise you likely need to override the action you want the different kwarg on and pass that down, overriding the necessary methods as you go. Ex.

def retrieve(self, request, *args, **kwargs):
  instance = self.get_object()
  serializer = self.get_serializer(instance, extra_option=...)
  return Response(serializer.data)

def get_serializer(self, *args, **kwargs):
  serializer_class = self.get_serializer_class(*args, **kwargs)
  kwargs.setdefault('context', self.get_serializer_context())
  return serializer_class(*args, **kwargs)

def get_serializer_class(self, *args, **kwargs):
  if kwargs.pop("extra_option", None):
    return ExtraOptionSerializer
  else:     
    return super().get_serializer_class()

Also check out classy DRF for reference: https://www.cdrf.co/3.13/rest_framework.viewsets/ModelViewSet.html#retrieve.

Edit: also self.serializer_class defaults to whatever you define on the view set so you likely want to instead call self.get_serializer_class(...) like you did with your custom method above.

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject