Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I call a view from within another view?

One of my view needs to add an item, along with other functionality, but I already have another view which specifically adds an item.

Can I do something like:

def specific_add_item_view(request):
    item = Item.objects.create(foo=request.bar)

def big_view(request):
    # ...
    specific_add_item_view(request)
like image 227
john2x Avatar asked Jan 26 '11 18:01

john2x


People also ask

Can we call a view from another view?

Yes, a view can be based on another view.

How do you call a view function in another view function in Django?

You can occasionally call view1 from view2 but if you do so it should be just return view1. The point is that you pass some additional params to view1 that it does not normally get from url (extra_context, template, success_url, ...). Here view2 acts as a proxy view for view1.

How do you call class based view in Django?

Asynchronous class-based viewsimport asyncio from django. http import HttpResponse from django. views import View class AsyncView(View): async def get(self, request, *args, **kwargs): # Perform io-blocking view logic using await, sleep for example. await asyncio.


4 Answers

Sure, as long as when it's all said and done your view returns an HttpResponse object. The following is completely valid:

def view1(request):
    # do some stuff here
    return HttpResponse("some html here")

def view2(request):
    return view1(request)

If you don't want to return the HttpResponse from the first view then just store it into some variable to ignore:

def view1(request):
    # do some stuff here
    return HttpResponse("some html here")

def view2(request):
    response = view1(request)
    # do some stuff here
    return HttpResponse("some different html here")
like image 125
brady Avatar answered Oct 31 '22 10:10

brady


View functions should return a rendered HTML back to the browser (in an HttpResponse). Calling a view within a view means that you're (potentially) doing the rendering twice. Instead, just factor out the "add" into another function that's not a view, and have both views call it.

def add_stuff(bar):
    item = Item.objects.create(foo=bar)
    return item

def specific_add_item_view(request):
    item = add_stuff(bar)
    ...

def big_view(request): 
    item = add_stuff(bar)
    ...
like image 39
Seth Avatar answered Oct 31 '22 10:10

Seth


Without class based views:

def my_view(request):
    return call_another_view(request)

def call_another_view(request):
    return HttpResponse( ... )

With class based views:

def my_view(request):
    return CallAnotherView.as_view()(request)

class CallAnotherView(View):
    ...
like image 13
Guilherme IA Avatar answered Oct 31 '22 12:10

Guilherme IA


A better way is to use the template system. Combining ideas from @Seth and @brady:

def specific_add_item_view(request, extra_context_stuff=None):
    Item.objects.create()
    context_variables = {} # obviously want to populate this
    if extra_context_stuff:
        context_variables.update(extra_context_stuff)
    return render(request, 'app_name/view1_template.html', context_variables)

def bigger_view(request):
    extra_context_stuff = {'big_view': True}
    return specific_add_item_view(request, extra_context_stuff)

And your app_name/view1_template.html might contain a conditional template tag

{% if big_view %}
<p>Extra html for the bigger view</p>
{% endif %}
like image 12
hobs Avatar answered Oct 31 '22 10:10

hobs