Django 4.1:从ModelForm创建User对象前排除字段报错
解决ModelForm新增confirm字段导致创建对象时的关键字参数错误
我有一个继承自自定义User模型的Patient用户类型,在ModelForm中新增了非模型字段confirm(用于确认密码),尝试在创建用户对象前移除该字段,但运行时出现错误:got unexpected keyword arguments: 'confirm'。相关代码如下:
models.py
class User(AbstractUser): username = None email = models.EmailField(unique=True) is_patient = models.BooleanField(default=False) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['password'] object = UserManager() class Patient(User): address = models.CharField(max_length=200) class Meta: verbose_name_plural = 'Patients' def __str__(self): return self.first_name
forms.py
class PateintForm(forms.ModelForm): confirm = forms.CharField(max_length=50, widget=forms.PasswordInput) is_patient = forms.BooleanField(widget=forms.HiddenInput) class Meta: model = Patient fields = ['first_name', 'last_name', 'address', 'email', 'password'] widgets = { 'first_name': forms.TextInput(attrs={'placeholder': 'First Name'}), 'last_name': forms.TextInput(attrs={'placeholder': 'Last Name'}), 'address': forms.TextInput(attrs={'placeholder': 'Address'}), 'email': forms.EmailInput(attrs={'placeholder': 'Email'}), 'password': forms.PasswordInput(attrs={'placeholder': 'Password'}) } def clean(self): cleaned_data = self.cleaned_data password = cleaned_data.get("password") confirm = cleaned_data.get("confirm") if confirm != password: self.add_error("password", "Passwords do not match.") self.add_error("confirm", "Passwords do not match.") if len(password) < 8: self.add_error("password", "Password must be greater than 8 letters.") if confirm == password and len(password) > 8: del cleaned_data['confirm'] return cleaned_data
views.py
def Patient(request): if request.method == "POST": form = PatientForm(request.POST, initial={'is_patient': True}) if form.is_valid(): Patient.objects.create(**form.cleaned_data) return HttpResponseRedirect('/Login/') else: for field in form.errors: form[field].field.widget.attrs['class'] += ' is-invalid' return render(request, 'Home/RegPatient.html', {'form': form}) else: form = PatientForm(initial={'is_patient': True}) return render(request, 'Home/RegPatient.html', {'form': form})
问题原因
原clean方法仅在密码匹配且长度达标时才删除confirm字段,一旦验证不通过(比如密码不匹配或长度不够),cleaned_data中会保留confirm键,传给Patient.objects.create()时,因模型无该字段触发关键字参数错误。
解决方案
1. 修正clean方法的字段处理逻辑
确保无论验证结果如何,都移除confirm字段,避免多余参数传入模型创建方法:
def clean(self): cleaned_data = super().clean() password = cleaned_data.get("password") confirm = cleaned_data.get("confirm") # 密码匹配验证 if confirm != password: self.add_error("password", "密码不匹配") self.add_error("confirm", "密码不匹配") # 密码长度验证 if password and len(password) < 8: self.add_error("password", "密码长度必须大于8位") # 安全移除confirm字段,即使字段不存在也不会报错 cleaned_data.pop('confirm', None) return cleaned_data
2. 正确创建用户(修复密码存储问题)
由于User模型继承自AbstractUser,直接用create()会明文存储密码,必须使用create_user()方法自动哈希密码:
def Patient(request): if request.method == "POST": form = PatientForm(request.POST, initial={'is_patient': True}) if form.is_valid(): user_data = form.cleaned_data # 单独取出密码,用create_user处理哈希 password = user_data.pop('password') patient = Patient.objects.create_user(password=password, **user_data) return HttpResponseRedirect('/Login/') else: for field in form.errors: form[field].field.widget.attrs['class'] += ' is-invalid' return render(request, 'Home/RegPatient.html', {'form': form}) else: form = PatientForm(initial={'is_patient': True}) return render(request, 'Home/RegPatient.html', {'form': form})
3. 修正表单类拼写错误
表单类名PateintForm应为PatientForm,避免调用时出现名称错误。
内容的提问来源于stack exchange,提问作者UmairKay
相关产品推荐
相关产品推荐

