提交Django表单时报错:Field 'id'期望数字却获取到QueryDict
咱们来一步步拆解这个问题:
错误根源
这个报错的核心原因是表单实例化时参数传递顺序完全错了。你的EmployeeForm的__init__方法把institute作为第一个必传参数,但在处理POST请求时,你直接把request.POST当成第一个参数传进去了,导致后续查询designation和department时,程序试图用QueryDict(也就是request.POST)去匹配institute_id这个数字字段,自然就会抛出"期望数字却得到QueryDict"的错误。
代码里的两处关键问题
表单
__init__方法没有正确传递父类参数
你的EmployeeForm的__init__里写了super().__init__(),没有把*args, **kwargs传给父类的构造方法,这会导致表单的POST数据和上传文件根本没被父类处理,表单验证完全失效。POST请求时表单实例化缺少
institute参数
在view的POST分支里,你写的form = EmployeeForm(request.POST, request.FILES),直接跳过了institute这个第一个必传参数,把request.POST塞给了institute参数的位置,这就直接导致了报错。
修复方案
第一步:修正EmployeeForm的__init__方法
把父类初始化的参数补全,确保表单能正确接收POST数据:
class EmployeeForm(forms.ModelForm): class Meta: model = Employee fields = '__all__' exclude = ['create', 'update', 'admin', 'user'] widgets = { 'date_of_birth': forms.DateInput(attrs={'type': 'date'}), } def clean_name(self): name = self.cleaned_data.get('name') if RiverTimeUser.objects.filter(username=name).count() > 0: raise ValidationError('This Employee Username is already in use.') return name def __init__(self, institute, *args, **kwargs): super().__init__(*args, **kwargs) # 这里必须传递*args和**kwargs self.helper = FormHelper() self.fields['designation'].queryset = Designation.objects.filter(institute_id=institute) self.fields['department'].queryset = Department.objects.filter(institute_id=institute)
第二步:修正view里的表单实例化逻辑
在POST分支里,把institute参数作为第一个参数传递给表单:
def employee_list(request): if request.POST and request.FILES: # 注意这里先传institute参数,再传POST和FILES form = EmployeeForm(request.user.institute.id, request.POST, request.FILES) if form.is_valid(): data = form.save(commit=False) # 建议用form.cleaned_data获取数据,更安全 username = form.cleaned_data.get('name') pin = form.cleaned_data.get('pin') data.user = RiverTimeUser.objects.create_user( username=username, pin=int(pin), password=pin ) data.save() messages.add_message(request, messages.SUCCESS, 'New Employee Added Successfully') context = { 'object_list': Employee.objects.filter(department__institute=request.user.institute), 'form': EmployeeForm(request.user.institute.id) } return render(request, 'employee.html', context=context)
额外小建议
在创建用户时,尽量使用form.cleaned_data来获取字段值,而不是直接从request.POST取,因为表单已经做过验证和清洗,这样的数据更可靠,也能避免一些类型转换的问题。
内容的提问来源于stack exchange,提问作者Riajul Kashem

