Django类视图(CBV)如何在post()方法外访问POST请求数据
核心原因
类属性template_name = chosen_tmplt_nm的赋值逻辑在服务启动、类加载阶段就会执行,此时还没有任何用户请求进入,不存在request对象,自然拿不到POST参数。同时你在post()方法内定义的chosen_tmplt_nm是方法局部变量,作用域仅在post方法内部,类定义层级无法访问到这个变量,所以你当前的写法根本无法生效。
最优实现方案(无需自定义post方法)
Django的TemplateView本身预留了动态获取模板名的钩子方法get_template_names(),这个方法会在请求进入、视图实例绑定了request对象之后,渲染模板前被调用,直接重写这个方法就能同时兼容GET、POST请求的参数读取,完全不需要自己重写post方法。
注意:直接使用用户传入的参数作为模板名存在路径遍历风险,必须加白名单做合法校验。
# views.py from django.views.generic import TemplateView from django.http import HttpResponseBadRequest class ReturnCustomTemplateView(TemplateView): # 配置默认兜底模板,参数缺失时使用 template_name = "default.html" # 配置允许访问的模板白名单,避免恶意传参 ALLOWED_TEMPLATES = { "user_center.html", "order_list.html", "goods_detail.html" } def get_template_names(self): # 同时支持POST、GET方式传模板名参数 input_tmplt = self.request.POST.get("tmplt_name") or self.request.GET.get("tmplt_name") if input_tmplt: if input_tmplt in self.ALLOWED_TEMPLATES: return [input_tmplt] return HttpResponseBadRequest("非法模板参数") return [self.template_name]
如果需要自定义post方法的写法
如果你的post方法里还要加其他业务逻辑,直接在方法内给当前视图实例的template_name属性赋值即可,赋值会覆盖类层面的属性值,注意要在模板渲染前完成赋值:
# views.py from django.views.generic import TemplateView from django.http import HttpResponseBadRequest from django.shortcuts import render class ReturnCustomTemplateView(TemplateView): template_name = "default.html" ALLOWED_TEMPLATES = { "user_center.html", "order_list.html", "goods_detail.html" } def post(self, request, *args, **kwargs): chosen_tmplt_nm = request.POST.get("tmplt_name") if chosen_tmplt_nm: if chosen_tmplt_nm not in self.ALLOWED_TEMPLATES: return HttpResponseBadRequest("非法模板参数") # 给当前请求对应的视图实例赋值,覆盖类属性 self.template_name = chosen_tmplt_nm context = self.get_context_data(**kwargs) return render(request, self.template_name, context)
提示:优先选择重写
get_template_names()的方案,这是Django CBV设计的标准扩展点,不需要重复实现响应渲染、上下文注入的逻辑,代码可维护性更高。
内容的提问来源于stack exchange,提问作者Anton Frolov
相关产品推荐
相关产品推荐

