我可以从另一个视图中调用视图吗?

我的一个视图需要添加一个项以及其他功能,但是我已经有了另一个专门添加项的视图。

我可以做这样的事情吗:

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


def big_view(request):
# ...
specific_add_item_view(request)
109321 次浏览

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")

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)
...

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 %}

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):
...

You can do like this:

def foo(req):
# code
def index(req):
return foo(req)

If you do this:

def calledView(bar):
...
return Response(...)


def base_view(request):
resp = add_stuff(request)
...

You will probably get this error:

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

So you should do this instead:

def calledView(request):
...
return Response(...)


def base_view(request):
resp = add_stuff(request._request)
...

My setup:

  • Python 3.9
  • Django 4

For class based views (all of them), this works:

class CheckoutPage(View):
    

template_name = "checkout.html"
def get(self, request):
prices = ViewAllPrices.as_view()(request)
return render(request, self.template_name, {'prices': prices})