Django CreateView上下文变量与表单显示冲突问题求助
Django CreateView表单与标题显示的两难问题
我用Django的CreateView展示表单,表单标题在admin面板设置。现在遇到两个问题:
- 第一种写法:表单正常显示,但模板里的
{{name}}(对应标题)为空 - 第二种写法:标题正常显示,但表单字段无法展示
模板代码(additem.html)
<div class="navbar"> <div class="image"> <img src="{% static 'images/logo.png' %}"> </div> <div class="text"> <h1>{{name}}</h1> </div> </div> <div class="card"> <form method="POST" action=""> {% csrf_token %} {{ form.as_p }} <input class="button" type="submit" value="Submit"> </form> </div>
第一种views.py写法(表单正常,标题为空)
class ItemCreate(CreateView): template_name = 'form/additem.html' model = Parts fields = ['number', 'item'] success_url = reverse_lazy('parts_list') def form_valid(self, form): username = self.request.user.get_full_name() form.instance.user = username form.instance.desc = getDescFromDB(form.cleaned_data['number']) return super(ItemCreate, self).form_valid(form) def get(self, request): match checkUserGroup(self.request.user): case "Service": return redirect("/") case "Shop": context = { 'name': getHeader('PartsForm') } return super().get(request, context)
第二种views.py写法(标题正常,表单不显示)
class ItemCreate(CreateView): template_name = 'form/additem.html' model = Parts fields = ['number', 'item'] success_url = reverse_lazy('parts_list') def form_valid(self, form): username = self.request.user.get_full_name() form.instance.user = username form.instance.desc = getDescFromDB(form.cleaned_data['number']) return super(ItemCreate, self).form_valid(form) def get(self, request): match checkUserGroup(self.request.user): case "Service": return redirect("/") case "Shop": context = { 'name': getHeader('PartsForm') } return render(request, self.template_name, context)
正常工作的辅助函数
def getHeader(form): title = Header.objects.get(name=form) return title.title def checkUserGroup(user): if (user.groups.filter(name='Service').exists()): return "Service" elif (user.groups.filter(name='Shop').exists()): return "Shop" else: raise PermissionDenied()
解决方案
问题根源
- 第一种写法中,调用
super().get(request, context)是错误的——父类get方法不接受context参数,自定义上下文未被传递,导致{{name}}为空。 - 第二种写法直接用
render返回模板,但未将CreateView自动生成的form对象加入上下文,所以表单无法渲染。
修复代码
不要重写get方法,改用dispatch做用户组校验,用get_context_data添加自定义上下文,既保留CreateView原有逻辑,又能同时传递标题和表单:
class ItemCreate(CreateView): template_name = 'form/additem.html' model = Parts fields = ['number', 'item'] success_url = reverse_lazy('parts_list') def dispatch(self, request, *args, **kwargs): # 前置用户组校验 match checkUserGroup(self.request.user): case "Service": return redirect("/") case "Shop": return super().dispatch(request, *args, **kwargs) def form_valid(self, form): username = self.request.user.get_full_name() form.instance.user = username form.instance.desc = getDescFromDB(form.cleaned_data['number']) return super(ItemCreate, self).form_valid(form) def get_context_data(self, **kwargs): # 获取父类生成的默认上下文(包含form对象) context = super().get_context_data(**kwargs) # 添加自定义标题变量 context['name'] = getHeader('PartsForm') return context
为什么可行?
dispatch是类视图的入口方法,在这里做校验能在请求处理前拦截不符合条件的用户,逻辑更合理。get_context_data是Django通用视图生成上下文的标准方法,重写它可安全添加自定义变量,同时保留原有上下文(包括自动生成的form),确保模板中{{name}}和{{form.as_p}}都能正常渲染。
内容的提问来源于stack exchange,提问作者Vidaloka
相关产品推荐
相关产品推荐

