Django从一个类视图调用另一类视图的请求方法问题
问题描述
我有两个绑定不同表单的类视图,需要在第一个表单提交成功后,跳转到第二个类视图对应的页面。
原始实现代码:
class FormsPreInput(CreateView): template_name = "form_preinput.html" def get(self, request, *args, **kwargs): form = preinput_form() return render(request, self.template_name, {"form": form}) def post(self, request, *args, **kwargs): form = preinput_form(request.POST) if form.is_valid(): return FormsInput.as_view()(request=self.request) class FormsInput(CreateView): template_name = "input_form.html" def get(self, request, *args, **kwargs): print("inside input get") def post(self, request, *args, **kwargs): print("inside post ")
遇到的问题:调用FormsInput时传入的是当前POST请求对象,代码会直接进入FormsInput.post()方法,完全不会执行FormsInput.get()里的逻辑。
问题原因
Django类视图的请求分发逻辑是根据当前请求的HTTP方法自动匹配对应处理函数的:收到POST请求就走post()方法,收到GET请求才会走get()方法。你在POST请求的处理流程里直接调用另一个类视图,传过去的还是原来的POST请求,自然不会触发GET逻辑。
另外你现在写的FormsInput的get、post方法都只打了日志没返回响应,实际跑起来会直接抛「视图未返回HttpResponse对象」的错误,这个也要一起修。
解决方法
不要在当前请求里直接调用另一个类视图,用重定向让客户端发新的GET请求到第二个视图的路由就可以了。
- 先给两个视图配置带命名的路由,示例:
# urls.py from django.urls import path from .views import FormsPreInput, FormsInput urlpatterns = [ path("pre-input/", FormsPreInput.as_view(), name="forms_pre_input"), path("input/", FormsInput.as_view(), name="forms_input"), ] - 修改第一个视图的POST逻辑,校验通过后直接重定向到第二个视图的路由:
from django.shortcuts import redirect, render from django.views.generic import CreateView # 导入你自己的表单类preinput_form、第二个页面对应的表单类 class FormsPreInput(CreateView): template_name = "form_preinput.html" def get(self, request, *args, **kwargs): form = preinput_form() return render(request, self.template_name, {"form": form}) def post(self, request, *args, **kwargs): form = preinput_form(request.POST) if form.is_valid(): # 如果需要把第一个表单的数据带到第二个页面,存在session里就行,别硬改request属性 # request.session["pre_form_cleaned"] = form.cleaned_data return redirect("forms_input") class FormsInput(CreateView): template_name = "input_form.html" def get(self, request, *args, **kwargs): print("inside input get") # 取前一个表单传的数就从session里pop,避免重复读取 # pre_data = request.session.pop("pre_form_cleaned", None) form = 第二个页面对应的表单类() return render(request, self.template_name, {"form": form}) def post(self, request, *args, **kwargs): print("inside post ") # 补全第二个表单的提交处理逻辑
注意事项
- 别尝试直接修改
request.method为GET来强行调用get方法,这种做法破坏了Django的请求处理流程,很容易触发中间件、请求上下文相关的诡异bug,重定向是最符合HTTP规范也最稳定的方案。 - 所有类视图的请求处理方法(get/post等)必须返回HttpResponse对象(比如render、redirect、JsonResponse的返回值),不能只写业务逻辑不返回内容。
内容的提问来源于stack exchange,提问作者Ankita
相关产品推荐
相关产品推荐

