自定义ModelForm__init__后无法使用instance参数的问题
问题:初始化带instance的ModelForm时报TypeError,需限制teacher字段可选范围
尝试为已有Course条目创建编辑表单,需限制ModelForm中teacher字段的可选用户范围,但使用instance=Course实例初始化表单加载预填数据时,出现错误:
TypeError at /courses/course/asdd CourseForm.__init__() got an unexpected keyword argument 'instance'
相关代码
view.py
@csrf_exempt @login_required def addCourse(request, course_id = None): #initialize data user = request.user school = user.school #check if submition is POST if request.method == 'POST': #if so check if user is linked to a school if user.school: #check if user has admin access to add courses if user.is_admin and user in school.admins: #get all form information # check if form data is valid if form.is_valid(): # save the form data to model form.save() return HttpResponseRedirect(reverse("courses", 'school')) #if GET check if user has a related school elif user.school: #check if user has admin access if user.is_admin: #check for course code, if so auto fill course info if course_id != None: #generate filled form course = Course.objects.get(code=course_id) form = CourseForm(instance=course, school=school) return render(request, "app/courses/addCourse.html", {'form': form}) #if no course code, generate blank form else: #generate form with school object to limit teacher options to school related users form = CourseForm(school) return render(request, "app/courses/addCourse.html", {'form': form}) #if all checks fail. Redirect. return HttpResponseRedirect(reverse("index"))
表单代码
class CourseForm(forms.ModelForm): class Meta(): model = Course fields = ('teacher','name','subject','level', 'description', 'start_time', 'end_time', 'start_date', 'end_date') widgets = { 'start_date': forms.DateInput(attrs={'type': 'date'}), 'end_date': forms.DateInput(attrs={'type': 'date'}), 'start_time': forms.TimeInput(attrs={'type': 'time'}), 'end_time': forms.TimeInput(attrs={'type': 'time'}), } def __init__(self, school, course=None): super(CourseForm, self).__init__() self.fields['teacher'] = forms.ModelChoiceField(widget=forms.Select, queryset=User.objects.filter(school=school, is_teacher=True))
补充:移除自定义__init__方法后,instance参数可正常使用,但无法将teacher字段的查询集限制为关联学校的用户。
解决方案
1. 修改表单的__init__方法,兼容ModelForm默认参数
自定义__init__需要接收所有ModelForm支持的参数(包括instance),并传递给父类,同时只需修改teacher字段的查询集即可,无需重新定义字段:
class CourseForm(forms.ModelForm): class Meta(): model = Course fields = ('teacher','name','subject','level', 'description', 'start_time', 'end_time', 'start_date', 'end_date') widgets = { 'start_date': forms.DateInput(attrs={'type': 'date'}), 'end_date': forms.DateInput(attrs={'type': 'date'}), 'start_time': forms.TimeInput(attrs={'type': 'time'}), 'end_time': forms.TimeInput(attrs={'type': 'time'}), } def __init__(self, school, *args, **kwargs): # 先调用父类初始化逻辑,处理instance等参数 super().__init__(*args, **kwargs) # 限制teacher字段的可选用户范围 self.fields['teacher'].queryset = User.objects.filter(school=school, is_teacher=True)
2. 调整视图中的表单调用方式
- 编辑场景(有course_id):
将参数调整为关键字参数或符合定义的顺序:
或者:form = CourseForm(school=school, instance=course)form = CourseForm(school, instance=course) - 新增场景:
原代码form = CourseForm(school)可保留,或改为form = CourseForm(school=school)增强可读性。
3. 修复POST请求中的表单初始化bug
当前POST分支未初始化form对象就判断form.is_valid(),会导致报错,需补上:
if request.method == 'POST': if user.school and user.is_admin and user in school.admins: # 初始化表单,传入school和POST数据 form = CourseForm(school, request.POST) if form.is_valid(): form.save() return HttpResponseRedirect(reverse("courses", args=['school']))
内容的提问来源于stack exchange,提问作者jimkwy
相关产品推荐
相关产品推荐

