I have a mobile app with a Django REST framework API and I have a lot of ModelViewSet that I call to retrieve data. I have performance issue because I need to call a lot of routes after the user login, and I would like to keep the REST logic but also returns after the login all the viewsets content in the login response (keeping their filters).
Is it possible to call a ModelViewset list() from another view (viewset or APIView)?
The only answer I found on SO was to do something like this
class ContentGenerator(APIView):
def get(self, request, format=None):
data = MyModelViewSet.as_view({'get': 'list'})(request).data
return Response({'data': data})
But it is not supported
Exception Value: The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`
Is there another solution?
To view all extra actions, call the .get_extra_actions () method. Extra actions can map additional HTTP methods to separate ViewSet methods. For example, the above password set/unset methods could be consolidated into a single route. Note that additional mappings do not accept arguments.
A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as .get () or .post (), and instead provides actions such as .list () and .create (). The method handlers for a ViewSet are only bound to the corresponding actions at the point of finalizing the view, using the .as_view () method.
The method handlers for a ViewSet are only bound to the corresponding actions at the point of finalizing the view, using the .as_view () method. Typically, rather than explicitly registering the views in a viewset in the urlconf, you'll register the viewset with a router class, that automatically determines the urlconf for you.
suffix - the display suffix for the viewset type - mirrors the detail attribute. name - the display name for the viewset. This argument is mutually exclusive to suffix. description - the display description for the individual view of a viewset. You may inspect these attributes to adjust behaviour based on the current action.
After some research, it looks like there might be side-effects to reuse the request in other views, so it is not officially supported by DRF. It is hacky, but if you know what you are doing, this is a solution.
data = MyModelViewSet.as_view({'get': 'list'})(request._request).data
I solved this in 2 ways. Assume I have a view A
and a viewset B
and that I want to call B.my_action
from A
. B.my_action
handles a specific id e.g. user id, product id etc.
1st way
code w/in BViewSet
@action(detail=True, methods=['post'])
def my_action(self, request, pk=None):
try:
# works when you call from web UI, through router
# automatically you have one specific view corresponding
# to specific id e.g. user id, product id etc
instance = self.get_object()
except AttributeError as ae:
# here you don't have a specific view instantiated
# and you have many ids e.g. user ids, product ids etc
# pick one id
instance = MyModelObject.objects.get(id=pk)
# rest of code as is, no change
code w/in e.g. AView.utils.py that calls BViewSet.my_action
Below request
is the request passed to AView
when AView
called
through web UI.
from django.http import HttpRequest
data = BViewSet(detail=True)
new_request = HttpRequest()
new_request.data = any_data_I_need_to_pass # e.g. request.data
ret = data.my_action(new_request, pk=request.data['id'])
return ret
2nd way
I decoupled my_action
functionality from my_action
call i.e.
code w/in BViewSet
@action(detail=True, methods=['post'])
def my_action(self, request, pk=None):
instance = self.get_object()
ret = my_action_server(instance, request.data)
return Response(data=ret)
def my_action_server(instance, data):
# all code comes here
return result
code w/in Aview
# import my_action_server as needed
# call my_action_server
# AView should provide everything needed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With