The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods, such as .get() and .post(), directly. This allows for more flexible composition of behavior.-Official Django Rest framework documentation
If you have used generic views before, then you have already used mixins. How? Let me show you.
The code above shows the generic way of building an API but still mixins are nowhere to be seen? 😕 Where is the mixins?
Let’s dig a little deep and see how generics are built. May be will find our answer there.
1
2
3
4
5
6
7
classCreateAPIView(mixins.CreateModelMixin,GenericAPIView):"""
Concrete view for creating a model instance.
"""defpost(self,request,*args,**kwargs):returnself.create(request,*args,**kwargs)
1
2
3
4
5
6
7
classListAPIView(mixins.ListModelMixin,GenericAPIView):"""
Concrete view for listing a queryset.
"""defget(self,request,*args,**kwargs):returnself.list(request,*args,**kwargs)
There you are mixins laying under the hoods. So generic views are also nothing but the product of multiple inheritance where it inherits classes from mixins with GenericAPIView.
Let’s dig a bit and see the mixins classes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classCreateModelMixin:"""
Create a model instance.
"""defcreate(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)returnResponse(serializer.data,status=status.HTTP_201_CREATED,headers=headers)defperform_create(self,serializer):serializer.save()defget_success_headers(self,data):try:return{'Location':str(data[api_settings.URL_FIELD_NAME])}except(TypeError,KeyError):return{}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classListModelMixin:"""
List a queryset.
"""deflist(self,request,*args,**kwargs):queryset=self.filter_queryset(self.get_queryset())page=self.paginate_queryset(queryset)ifpageisnotNone:serializer=self.get_serializer(page,many=True)returnself.get_paginated_response(serializer.data)serializer=self.get_serializer(queryset,many=True)returnResponse(serializer.data)
1
2
3
4
5
6
7
8
classRetrieveModelMixin:"""
Retrieve a model instance.
"""defretrieve(self,request,*args,**kwargs):instance=self.get_object()serializer=self.get_serializer(instance)returnResponse(serializer.data)
classUpdateModelMixin:"""
Update a model instance.
"""defupdate(self,request,*args,**kwargs):partial=kwargs.pop('partial',False)instance=self.get_object()serializer=self.get_serializer(instance,data=request.data,partial=partial)serializer.is_valid(raise_exception=True)self.perform_update(serializer)ifgetattr(instance,'_prefetched_objects_cache',None):# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache={}returnResponse(serializer.data)defperform_update(self,serializer):serializer.save()defpartial_update(self,request,*args,**kwargs):kwargs['partial']=Truereturnself.update(request,*args,**kwargs)
1
2
3
4
5
6
7
8
9
10
11
classDestroyModelMixin:"""
Destroy a model instance.
"""defdestroy(self,request,*args,**kwargs):instance=self.get_object()self.perform_destroy(instance)returnResponse(status=status.HTTP_204_NO_CONTENT)defperform_destroy(self,instance):instance.delete()
Conclusion: So what mixins offer is action. The action like list, retrieve, create, update and destroy. The behaviour we use to define inside simple function based view and class based api view is now defined by mixins itself. We can say that the common patterns generic views support without having to write code by developer themselves is mixins under the hoods and to be more specific “actions”.
Leave a comment