Invoke function after all methods Django Rest Framework ModelViewSet - python

I would like to invoke a function after all methods in a ModelViewSet. The function itself will be used as an external event log. So the response from the views would not be modified. I was not able to figureout how to achieve this. My ModelViewSet is a very basic one with serializer class and queryset defined.
Any help would be appreciated.

Override the dispatch method of view.
class MyDRFView(...):
def my_custom_logging_method(self, request, response, *args, **kwargs):
# do something useful here.....
...
def dispatch(self, request, *args, **kwargs):
response = super().dispatch(request, *args, **kwargs)
self.my_custom_logging_method(request, response, *args, **kwargs)
return respons

You can always override any python class. Overriding all the method can be little trickier and I guess will just create unnecessary logs. You should only override the method that is really of importance. Here is an example:
class LoggingModelViewSet(viewsets.ModelViewSet):
def perform_create(self, serializer):
print('Invoked perform_create')
serializer.save(owner=self.request.user)
def finalize_response(self, request, response, *args, **kwargs):
xresponse = super().finalize_response(request, response, *args, **kwargs)
print('finalize_response', xresponse)
return xresponse
and more like this... you should see the source here https://github.com/encode/django-rest-framework/blob/master/rest_framework/viewsets.py#L217 It is not so tricky.

Related

Move some code from GenericAPIView post method to other methods in django

I have my django GenericAPIView with post method, I want some part of the logic which uses self to be in some other method and exccute that code when my post method gets hit
class MyAPIView(GenericAPIView):
def post(self, request, *args, **kwargs):
You can do something like this!
class MyAPIView(CreateAPIView):
def custom_function(self):
"""place your logic here!"""
pass
def post(self, request, *args, **kwargs):
# This will call our custom function as soon as post request is hit
self.custom_function()
return super().post(request, *kwargs, *args)

how to override the .create() method inside a generic view (example: ListCreateAPIView) in django-rest-framework?

I wanted to override the create method in class-based view which implements the ListCreateAPIView , not generally while overriding methods like the get_queryset(self) method, the requests, the url **kwargs are accessed from self, but I wanted to override the .create() method of the CreateModelMixin, so I took a look at the code to find the signature as create(self, request, *args, **kwargs) what does django pass in the **kwargs, *args of this function? are these url **kwargs by any chance? How do I go about overriding the create method in the generic view asthe request in any function of the generic view is accessed from the self but the signature of the create function explicitly requires a request argument.
Following is DRF ListCreateAPIView, as you can see *args, **kwargs are directly passing down from standard post method:
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset or creating a model instance.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
Now, talking about overriding create from CreateModelMixin, you can simply override it as:
from rest_framework import generics
class YourWonderfulView(generics.ListCreateAPIView):
queryset = YourModelClass.objects.all()
serializer_class = YourSerializer
def create(self, request, *args, **kwargs): # don't need to `self.request` since `request` is available as a parameter.
# your custom implementation goes here
return Response(response) # `response` is your custom response – e.g. dict, list, list of dicts etc
Hope it helps :)
from rest_framework import generics
from tasks.models import Task
from tasks.serializers import TaskSerializer
class TaskList(generics.ListCreateAPIView):
queryset = Task.objects.all()
serializer_class = TaskSerializer
def create(self, request, *args,**kwargs):
# your implementation
return Response(response)

Use #staticmethod in Django Rest Framework endpoint method?

Should I be defining post, get, etc methods of a Django Rest Framework APIView as static?
class HomeView(APIView):
def get(request):
etc...
or
class HomeView(APIView):
#staticmethod
def get(request):
etc...
What are the pros/cons of each way?
Thank you
DRF does not declare get and post as static methods and neither should you. Here's how the defaults are configured in DRF generics.
It is common in DRF to reference instance methods such as self.get_object and self.get_serializer from within get and post.
class CreateAPIView(mixins.CreateModelMixin,
GenericAPIView):
"""
Concrete view for creating a model instance.
"""
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class RetrieveAPIView(mixins.RetrieveModelMixin,
GenericAPIView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
class DestroyAPIView(mixins.DestroyModelMixin,
GenericAPIView):
"""
Concrete view for deleting a model instance.
"""
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
class UpdateAPIView(mixins.UpdateModelMixin,
GenericAPIView):
"""
Concrete view for updating a model instance.
"""
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
As DRF document, You seems do not need to add #staticmethod decorator
DRF won't function correctly without passing ' self '.
PyCharm does mark these methods as 'maybe static', this is false!
Making them static breaks the calling of the method, since the caller method provides the 'self', and your method does not except it. Essentially your still get the self aliased as request, but your other args are ignored. It is possible that this happens silently, that makes it a fairly nasty bug to find :(.
In terms of performance a 'static' or regular function based view should be slightly faster, since you avoid the creation of the instance, but the difference is probably so small that it is hardly noticeable.

Django class view: __init__

I want to get <Model> value from a URL, and use it as an __init__ parameter in my class.
urls.py
url(r'^(?P<Model>\w+)/foo/$', views.foo.as_view(), name='foo_class'),
views.py
class foo(CreateView):
def __init__(self, **kwargs):
text = kwargs['Model'] # This is not working
text = kwargs.get('Model') # Neither this
Bar(text)
...
Clearly, I'm missing something, or my understanding of URL <> class view is wrong.
You should override dispatch method for such use cases.
class Foo(CreateView):
def dispatch(self, request, *args, **kwargs):
# do something extra here ...
return super(Foo, self).dispatch(request, *args, **kwargs)
For your specific scenario, however, you can directly access self.kwargs as generic views automatically assign them as an instance variable on the view instance.

Dajaxice with Class Based View

Is there a way to user dajaxice with django class based views?
I'm trying this, but not having much success:
class FavoriteEnroledTrainee(SessionMixin, View):
def get(self, request, *args, **kwargs):
print 'here'
#method_decorator(dajaxice_register(method='GET', name='company.favorite'))
def dispatch(self, *args, **kwargs):
return super(FavoriteEnroledTrainee, self).dispatch(*args, **kwargs)
I can see the dajaxice is able to fetch the view but nothing gets printed.
You cannot register the dispatch method, because it's not the view entry point. Dajaxice will try to call dispatch directly, but this won't work because it's not a fully functionnal view.
You should register the result of the *as_view* call :
class FavoriteEnroledTrainee(SessionMixin, View):
def get(self, request, *args, **kwargs):
print 'here'
favorite_enroled_trainee = dajaxice_register(method='GET', name='company.favorite')(FavoriteEnroledTrainee.as_view())

Categories