Where does the self.get_serializer method come from in the Django REST Framework?

Question:

In the DRF source code, there’s a get_serializer method. It wasn’t inherited from object and it’s not a method in the CreateModelMixin class. Where does this method come from?

serializer = self.get_serializer(data=request.data)

Here’s the larger chunk of code for context.

from __future__ import unicode_literals

from rest_framework import status
from rest_framework.response import Response
from rest_framework.settings import api_settings


class CreateModelMixin(object):
    """
    Create a model instance.
    """
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        serializer.save()

    def get_success_headers(self, data):
        try:
            return {'Location': data[api_settings.URL_FIELD_NAME]}
        except (TypeError, KeyError):
            return {}

There are a few SO posts that that also use this method. Like this, this, and this. But I still can’t figure out where the implementation is.

Asked By: k-mad

||

Answers:

You can see the __file__ or __module__ member of the method (if it has them) to learn that. inspect also has getsourcefile and getsourcelines that use data from the function’s code object, specifically, <function>.f_code.co_filename and .co_firstline.

For example, this retrieves source information for a method inherited from DictMixin:

>>> c=ConfigParser._Chainmap()
>>> f=c.__len__
>>> dump(f.__code__)    # my custom function that dumps attributes,
                        # see https://github.com/native-api/dump
<...>
co_filename : /usr/lib/python2.7/UserDict.py
co_firstlineno : 179
<...>

# same with inspect
>>> inspect.getsourcefile(f)
'/usr/lib/python2.7/UserDict.py'
>>> inspect.getsourcelines(f)
(['    def __len__(self):n', '        return len(self.keys())n'], 179)
>>> inspect.getsource(f)
'    def __len__(self):n        return len(self.keys())n'

# same with __file__
>>> sys.modules[f.__module__].__file__
'/usr/lib/python2.7/UserDict.pyc'
Answered By: ivan_pozdeev

CreateModelMixin along with all other mixin classes (Eg. ListModelMixin, UpdateModelMixin etc) are defined in rest_framework/mixins.py file.

These mixin classes provide all the basic CRUD operations on a model. You just need to define a serializer_class and queryset in your generic view to perform all these operations. DRF has separated out these common functionality in separate mixin classes so that they can be injected/mixed-in in a view and used as and when required.

In the DRF source code, there’s a get_serializer method. It wasn’t
inherited from object and it’s not a method in the CreateModelMixin
class. Where does this method come from?

In the GenericAPIView, get_serializer method is defined. The combination of different mixin classes along with GenericAPIView class provide us different generic views for different use cases.

class GenericAPIView(views.APIView):
    """
    Base class for all other generic views.
    """

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)

Other generic views then inherit the relevant mixin along with GenericAPIView.

Eg. CreateAPIView inherit the CreateModelMixin along with GenericAPIView to provide create-only endpoints.

# rest_framework/generics.py
class CreateAPIView(mixins.CreateModelMixin,
                    GenericAPIView):
    ...
Answered By: Rahul Gupta

It helps if you understand class inheritance (not suggesting you don’t, though).

CreateModelMixin will be used by a class based view, for example:

class YourViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):

get_serializer is a method available through GenericViewSet (although there are probably other View classes that it’s available on, too).

So, basically if you would use CreateModelMixin only get_serializer would not be available. (You probably wouldn’t do that anyway). It’s only because you inherit from another class besides CreateModelMixin that the get_serializer method is available at the moment that the create method is executed.

I could give a simple example of what’s happening, while I am at it. It’s just to give a more simple overview of what’s happening.

disclaimer: you might want to keep in mind that I am a junior developer, so this may not be the most Pythonic code out there :P.

class MyMixin:
    def create(self):
        serializer = self.get_serializer()
        return serializer


class FakeView:
    def get_serializer(self):
        return "Sadly I am just a string, but I could've been a serializer."


class MyFakeView(MyMixin, FakeView):
    pass

view = MyFakeView()

serializer = view.create()

print(serializer)

executing this would show you:

Sadly I am just a string, but I could've been a serializer.

Where if you would define MyFakeView like below,

class MyFakeView(MyMixin):
    pass

you would receive the following error:

AttributeError: 'MyFakeView' object has no attribute 'get_serializer'

Answered By: Rik Schoonbeek
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.