Where does the self.get_serializer method come from in the Django REST Framework?
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 theCreateModelMixin
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):
...
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'
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'