Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework- calling another class-based view

I have pored over several similar posts (and Calling a class-based view of an app from another app in same project seemed promising, but does not work), but some are older and none quite work for me. Here's my setup (using Django==2.0.6, djangorestframework==3.8.2)

I have a basic model (simplified here):

from django.db import models
class Resource(models.Model):
    name = models.CharField(max_length=100, null=False)

I have a basic endpoint where I can list and create Resource instances:

from rest_framework import generics, permissions
from myapp.models import Resource
from myapp.serializers import ResourceSerializer

class ListAndCreateResource(generics.ListCreateAPIView):
    queryset = Resource.objects.all()
    serializer_class = ResourceSerializer
    permission_classes = (permissions.IsAuthenticated,)

(afaik, the details of the serializer are not relevant, so that is left out).

Anyway, in addition to that basic endpoint, I have another API endpoint which performs some actions, but also creates some Resource objects in the process. Of course, I would like to make use of the functionality encapsulated in the ListAndCreateResource class so I only have to maintain one place where Resources are created.

I have tried:

Attempt 1:

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource().post(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

Unfortunately, that does not work for me. In my trace, I get:

  File "/home/projects/venv/lib/python3.5/site-packages/rest_framework/generics.py", line 111, in get_serializer
    kwargs['context'] = self.get_serializer_context()
  File "/home/projects/venv/lib/python3.5/site-packages/rest_framework/generics.py", line 137, in get_serializer_context
    'request': self.request,
AttributeError: 'ListAndCreateResource' object has no attribute 'request'

Attempt 2: This attempt tries to use the as_view method which is part of all Django class-based views:

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource.as_view()(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

But that gives up with:

AssertionError: The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`

So my question is...is there a straightforward way to do this? I can access the _request attribute of the rest_framework.request.Request object (which is of type django.http.HttpRequest, but then I do not have any of the authentication details that are contained in the DRF Request object (indeed, my ListAndCreateResource returns a 403 if I use response = ListAndCreateResource().as_view()(request._request, *args, **kwargs) in attempt #2 above).

Thanks in advance!

like image 881
blawney_dfci Avatar asked Jul 03 '18 01:07

blawney_dfci


People also ask

How do you use class based views in Django REST Framework?

To make use of generic class-based views, the view classes should import from rest_framework. generics. ListAPIView: It provides a get method handler and is used for read-only endpoints to represent a collection of model instances. ListAPIView extends GenericAPIView and ListModelMixin.

What is difference between APIView and Viewset?

APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.

What is APIView in DRF?

Function-based Views @api_view is a decorator that converts a function-based view into an APIView subclass (thus providing the Response and Request classes). It takes a list of allowed methods for the view as an argument. Curious how DRF converts function-based views into APIView subclasses?


1 Answers

This seems a bit late, but in case anyone is wondering.

class SomeOtherView(generics.CreateAPIView):
    def post(self, request, *args, **kwargs):
        # ... some other functionality...
        # ...
        response = ListAndCreateResource.as_view()(request, *args, **kwargs)
        # ... more functionality...
        return Response({'message': 'ok'})

The as_view() is a function that when called, returns a function that takes a request, *args, **kwargs. So basically, a class view is an encapsulated function view.

like image 115
Ahmed I. Elsayed Avatar answered Oct 20 '22 01:10

Ahmed I. Elsayed