67

I have the following generic class based views built with Django Rest framework (DRF)

class ExampleDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Example.objects.all()
    serializer_class = ExampleSerializer
    renderer_classes = (JSONRenderer, TemplateHTMLRenderer)

    def get(self, request, *args, **kwargs):

        response = self.retrieve(request, *args, **kwargs)
        if request.accepted_renderer.format == 'html':
            form = ExampleForm(data=response.data)
            return Response({'data': response.data, 'form': form}, template_name='example.html')

        return response

This view allow me to obtain both JSON data or HTML form from the same endpoint by specifying the format=json or html.

I would like to programmatically call that view to obtain the rendered HTML form from within another view in order to include this form in another page that will include more stuff.

5 Answers 5

42

I found the solution for this in the documentation... https://docs.djangoproject.com/en/4.1/ref/class-based-views/mixins/

Hint is from their example here:

class AuthorDetail(View):

    def get(self, request, *args, **kwargs):
        view = AuthorDisplay.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = AuthorInterest.as_view()
        return view(request, *args, **kwargs)
Sign up to request clarification or add additional context in comments.

4 Comments

Does not work. I get The `request` argument must be an instance of `django.http.HttpRequest`, not `rest_framework.request.Request`.
It's certainly possible both projects have diverged in how they treat things ... I haven't played with this in awhile.
Looks like someone (Greg Brown) proposed an edit that those calls should be return view(request._request, *args, **kwargs) -- maybe that is the "newer" way to do it, @waqasgard...worth trying I think. Leaving the answer as-is, since it matches the linked documentation and was valid for older versions of Django.
Here's the link to the 4.0 documentation: docs.djangoproject.com/en/4.0/topics/class-based-views/mixins/… It has the same example.
36
html_from_view = ExampleDetail.as_view({'get': 'list'})(request).content

OR

html_from_view = ExampleDetail.as_view({'get': 'retrieve'})(request, pk=my_id).render().content

6 Comments

what is the request ? , and if I'm in one ipython shell
@Sérgio Read the question. The request is the same that was passed to the original view function / get method. If you are in a ipython shell, you have to use another approach. For example, you can emulate a http request using the django test client. docs.djangoproject.com/en/2.0/topics/testing/tools/…
The above works now, 5 years later, except use request._request instead of request.
This solution works for the ViewSet but not APIView. The solution provided by JD Solanki below works for APIView.
But how do you create the HttpRequest object programmatically with a body when the body is read-only? An HttpRequest object is required. And for POST requests with a body there appears to be no way whatsoever to create the body programmatically.
|
23

As of Django 2.2 and DRF 3.9.2 I am able to get response using below code.

response = UserItemsApiView.as_view()(request=request._request).data

Above example solves below issues:

  • The request argument must be an instance of django.http.HttpRequest, not rest_framework.request.Request
  • Instead of content, using data attribute gave me result from that view.

2 Comments

I get "b'{"detail":"CSRF Failed: CSRF token missing or incorrect."}'" when trying this, any idea why?
Need to use .as_view({'get': 'retrieve'}), but otherwise this works. In my case I'd like the list of objects so I use .as_view({'get': 'list'}).
2

The syntax of some of the answers was confusing to me, even though that's how the django docs explain it:

https://docs.djangoproject.com/en/4.1/ref/class-based-views/base/#django.views.generic.base.View.as_view

So here's an answer that's a little more understandable for my small brain:

class MyTemplateView(TemplateView):
    template_name = 'my_template.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        view = MyApiView.as_view()
        response = view(request=self.request)
        data = response.data
        context["somedata"] = data
        return context

Comments

-10

If I'm understanding correctly, you need to get the result from view B, while inside view A.

Using the requests/urllib2 and json libraries should solve your problem (as specified in this answer).

To get the URL, you can use a combination of request.get_absolute_uri() and/or request.get_host() and django.core.urlresolvers.reverse.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.