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

在Django表单中添加模型未含字段时触发KeyError问题排查

解决Django表单中添加额外字段(school)的KeyError问题

问题场景

我有一个用于存储学生数据的Student模型,代码如下:

Models.py

class Student(models.Model):
    roll_no = models.IntegerField(editable=True, blank=False, primary_key=True)
    name = models.CharField(max_length=30)
    date_of_birth = models.DateField(default='1900-01-01', blank=True)
    admission_no = models.IntegerField(default=roll_no)
    admission_date = models.DateField(default=datetime.now)
    student_cnic = models.CharField(max_length=15)
    father_cnic = models.CharField(max_length=15)
    grade = models.ForeignKey('school.SchoolClasses', on_delete=models.CASCADE, null=True, blank=True)
    mobile = models.CharField(max_length=12)
    active = models.BooleanField(default=True)

对应的Student表单代码如下:

Forms.py

class StudentForm(forms.ModelForm):

    extra_fields = ['school']

    class Meta:
        model = Student
        fields = ['roll_no', 'name', 'date_of_birth', 'admission_no', 'admission_date', 'student_cnic', 'father_cnic',
                  'mobile', 'grade']


    def __init__(self, *args, **kwargs):
        super(StudentForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(Row(Column('roll_no', css_class='form-group col-md-6'),
                                        Column('admission_no', css_class='form-group col-md-6'), ),
                                    Row(Column('date_of_birth', css_class='form-group col-md-6'),
                                        Column('admission_date', css_class='form-group col-md-6'), ),
                                    Row(Column('name', css_class='form-group col-md-3'),
                                        Column('student_cnic', css_class='form-group col-md-3'),
                                        Column('father_cnic', css_class='form-group col-md-3'),
                                        Column('mobile', css_class='form-group col-md-3'), ),
                                    Row(
                                        Column('school', css_class='form-group col-md-3'),
                                        Column('grade', css_class='form-group col-md-3'),
                                    ),
                                    Submit('submit', 'Add Student', css_class='btn btn-primary'), )

        self.fields['date_of_birth'].widget = forms.DateInput(attrs={'type': 'date'})
        self.fields['admission_date'].widget = forms.DateInput(attrs={'type': 'date'})

我添加school字段是为了过滤grade字段的选项,仅显示所选学校下的年级,但出现了如下错误:

KeyError: "Key 'school' not found in 'StudentForm'. Choices are: admission_date, admission_no, date_of_birth, father_cnic, grade, mobile, name, roll_no, student_cnic."

问题原因

你只声明了extra_fields = ['school'],但并没有在表单中实际定义这个字段,Django表单无法识别不存在的字段,因此抛出KeyError。要实现学校过滤年级的功能,需要先显式添加school字段,再动态过滤grade的选项。

解决步骤

1. 显式添加school字段

首先导入学校模型(假设你的学校模型是school.models.School),然后在StudentForm类中添加school字段:

from school.models import School, SchoolClasses

class StudentForm(forms.ModelForm):
    # 显式添加school字段,用于选择学校
    school = forms.ModelChoiceField(queryset=School.objects.all(), required=True, label='学校')
    
    class Meta:
        model = Student
        fields = ['roll_no', 'name', 'date_of_birth', 'admission_no', 'admission_date', 'student_cnic', 'father_cnic',
                  'mobile', 'grade']
    
    # 其余代码保留

2. 动态过滤grade字段的选项

在__init__方法中,根据选中的学校过滤grade(即SchoolClasses)的选项,编辑已有学生时自动匹配对应学校:

def __init__(self, *args, **kwargs):
    super(StudentForm, self).__init__(*args, **kwargs)
    self.helper = FormHelper()
    self.helper.layout = Layout(Row(Column('roll_no', css_class='form-group col-md-6'),
                                    Column('admission_no', css_class='form-group col-md-6'), ),
                                Row(Column('date_of_birth', css_class='form-group col-md-6'),
                                    Column('admission_date', css_class='form-group col-md-6'), ),
                                Row(Column('name', css_class='form-group col-md-3'),
                                    Column('student_cnic', css_class='form-group col-md-3'),
                                    Column('father_cnic', css_class='form-group col-md-3'),
                                    Column('mobile', css_class='form-group col-md-3'), ),
                                Row(
                                    Column('school', css_class='form-group col-md-3'),
                                    Column('grade', css_class='form-group col-md-3'),
                                ),
                                Submit('submit', 'Add Student', css_class='btn btn-primary'), )

    self.fields['date_of_birth'].widget = forms.DateInput(attrs={'type': 'date'})
    self.fields['admission_date'].widget = forms.DateInput(attrs={'type': 'date'})
    
    # 初始化年级选项
    school_id = None
    if self.instance.pk and self.instance.grade:
        # 编辑已有学生时,获取对应学校ID
        school_id = self.instance.grade.school_id
        self.fields['school'].initial = school_id
    
    # 根据学校ID过滤年级
    if school_id:
        self.fields['grade'].queryset = SchoolClasses.objects.filter(school_id=school_id)
    else:
        self.fields['grade'].queryset = SchoolClasses.objects.none()

3. 处理表单提交逻辑

由于school不是Student模型的字段,提交时需要移除该字段的数据,避免报错:

def save(self, commit=True):
    # 移除school字段的清理数据
    self.cleaned_data.pop('school', None)
    return super().save(commit=commit)

4. 前端AJAX动态更新(可选)

如果需要用户选择学校后立即更新年级选项,可添加AJAX逻辑:

  • 在模板中为school下拉框添加onchange事件,发送请求到后端
  • 编写视图函数接收学校ID,返回对应年级的JSON数据
  • 前端通过JS更新grade下拉框的选项

总结

核心问题是未在表单中实际定义school字段,只需显式添加该字段,再通过代码动态过滤年级选项,即可解决KeyError并实现学校过滤年级的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 04:10:38