You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django FormView表单无效时get_context_data抛KeyError如何解决

问题根源分析

你遇到的报错和上下文异常问题核心来自3个逻辑错误:

  1. super调用错误:get_context_data中super的第一个参数写的是CredentialsView,而非当前类TestView,会导致父类上下文获取逻辑异常
  2. 核心KeyError原因:表单校验失败时触发form_invalid逻辑,此时当前请求是POST方法,你直接将POST请求传入仅绑定了get动作的TestViewSet,导致ViewSet没有返回预期的包含用户信息的结构,data字典中不存在username键
  3. 冗余逻辑:form_valid方法是表单校验通过后才会触发的钩子,无需在内部再次调用form.is_valid()判断

解决方案

问题1:表单校验无效时正常获取上下文数据

优先直接从当前登录用户对象读取属性,避免跨ViewSet调用带来的请求方法兼容问题,修改后代码如下:

class TestView(LoginRequiredMixin, FormView):
    form_class = TestForm
    template_name = 'test.html'

    def get_context_data(self, **kwargs):
        # 修正super调用的类名
        context = super(TestView, self).get_context_data(**kwargs)
        # LoginRequiredMixin已经保证用户登录,该判断可按需保留
        if self.request.user.is_authenticated:
            # 直接从当前登录用户对象取属性,无请求方法兼容问题
            context['username'] = self.request.user.username
            context['firstname'] = self.request.user.first_name
            context['lastname'] = self.request.user.last_name
            
            # --- 如果必须调用TestViewSet获取数据,使用以下兼容代码 ---
            # from rest_framework.request import Request
            # 构造GET请求副本,适配ViewSet的get动作要求
            # get_request = Request(self.request._request)
            # get_request.method = 'GET'
            # data = TestViewSet.as_view({'get': 'list'})(get_request).data
            # 增加安全判断避免KeyError
            # context['username'] = data.get('username', '')
            # context['firstname'] = data.get('firstname', '')
            # context['lastname'] = data.get('lastname', '')
        return context

    def form_valid(self, form):
        password = form.cleaned_data['password']
        # 移除冗余的is_valid判断,form_valid触发时已经校验通过
        return self.query_api(password)

问题2:表单校验无效时返回错误信息到HTML页面

Django的FormView原生form_invalid方法已经自动将携带错误信息的form对象注入到上下文的form变量中,不需要额外编写视图逻辑,直接在模板中按以下方式渲染即可:

<form method="post">
    {% csrf_token %}
    <!-- 渲染全局非字段错误 -->
    {% if form.non_field_errors %}
    <div class="error-box">
        {% for error in form.non_field_errors %}
        <p>* {{ error }}</p>
        {% endfor %}
    </div>
    {% endif %}
    
    <!-- 渲染单个表单字段及对应错误 -->
    <div class="form-item">
        <label>密码</label>
        <input type="password" name="password" value="{{ form.password.value|default:'' }}">
        {% if form.password.errors %}
        <span class="error-tip">{{ form.password.errors.0 }}</span>
        {% endif %}
    </div>
    
    <button type="submit">提交</button>
</form>
  • 非字段相关的全局错误存储在form.non_field_errors中
  • 字段级错误存储在对应字段的errors属性中,字段的已输入值可通过form.字段名.value读取回填

内容的提问来源于stack exchange,提问作者Aditya Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 22:51:01