Django表单提交报错:__init__() 参数'user'收到多个值
解决Django表单初始化时的参数冲突问题
问题现象
在实现带用户筛选的ModelChoiceField时,自定义表单__init__方法后,提交表单出现错误:
"init() got multiple values for argument 'user'"
错误原因
表单的__init__方法将user作为位置参数放在了*args前面,而Django表单初始化时,第一个位置参数默认接收表单数据(比如POST请求的request.POST)。当调用WorkLogForm(request.POST, user=request.user)时,request.POST会被赋值给user参数,同时又通过关键字参数传递了user=request.user,导致同一个参数被重复传递,引发冲突。
解决方案
修改forms.py的__init__方法
将user改为从关键字参数中获取,避免位置参数冲突:
class WorkLogForm(forms.ModelForm): worklog_date = forms.DateField(label='Дата', widget=forms.DateInput( attrs={'class': 'form-control', 'placeholder': 'Введите дату'})) author = forms.EmailField(label='Автор', widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email автора'})) contractor_counter = forms.ModelChoiceField(queryset=CounterParty.objects.none()) contractor_object = forms.ModelChoiceField(queryset=ObjectList.objects.none()) contractor_section = forms.ModelChoiceField(queryset=SectionList.objects.none()) description = forms.CharField(label='Описание', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Описание'})) def __init__(self, *args, **kwargs): # 从关键字参数中取出user,确保调用时必传 user = kwargs.pop('user') super().__init__(*args, **kwargs) counter_queryset = CounterParty.objects.filter(counter_user=user) object_queryset = ObjectList.objects.filter( Q(customer_guid__in=counter_queryset) | Q(contractor_guid__in=counter_queryset)) section_queryset = SectionList.objects.filter(object__in=object_queryset) self.fields['contractor_counter'].queryset = counter_queryset self.fields['contractor_object'].queryset = object_queryset self.fields['contractor_section'].queryset = section_queryset class Meta: model = WorkLog fields = ( 'worklog_date', 'author', 'contractor_counter', 'contractor_object', 'contractor_section', 'description')
修正views.py中的赋值错误
原代码中直接修改form.author的方式不符合Django表单规范,应通过save(commit=False)修改实例:
def create_work_log(request): if request.method == 'POST': form = WorkLogForm(request.POST, user=request.user) if form.is_valid(): work_log = form.save(commit=False) # 若author字段存储邮箱,赋值request.user.email;若为User外键,直接赋值request.user work_log.author = request.user.email work_log.save() return render(request, 'common/home.html') else: form = WorkLogForm(user=request.user) return render(request, 'contractor/create_work_log.html', {'form': form})
说明
修改后,无论GET还是POST请求,调用表单时都通过关键字参数user=request.user传递用户,既避免了参数冲突,也符合Django表单的初始化规范。
内容的提问来源于stack exchange,提问作者Zesshi
相关产品推荐
相关产品推荐

