Django自定义用户模型存表单数据报错:User()收到意外关键字参数
问题原因
你遇到的错误是因为自定义User模型中没有speciality、department这些字段,但你把表单里所有字段(包括学生专属字段)都传给了User.objects.create_user()方法,导致User模型无法识别这些额外参数。
由于你设计了Student和Teacher两种用户类型,正确的做法是:基础User模型只保存通用字段(用户名、邮箱、密码等),学生专属字段(speciality、department等)应该放在单独的Student模型中,通过一对一关联和User绑定。
解决步骤
1. 确认模型结构(示例)
假设你的自定义User模型和Student模型如下(如果还没定义,先补上):
from django.contrib.auth.models import AbstractUser from django.db import models # 基础自定义用户模型,只存储通用字段 class User(AbstractUser): pass # 学生专属模型,与User一对一关联 class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='student_profile') nation = models.CharField(choices=NATIONALITY_CHOICES, blank=True, max_length=50) sex = models.CharField(choices=SEX_CHOICES, blank=True, max_length=10) phone = models.CharField(max_length=50) address = models.CharField(max_length=50) department = models.CharField(choices=DEPARTMENT_CHOICES, blank=True, max_length=50) speciality = models.CharField(choices=SPECIALITY_CHOICES, blank=True, max_length=50) shift = models.CharField(choices=SHIFT_CHOICES, blank=True, max_length=20) plan = models.CharField(choices=TYPE_CHOICES, blank=True, max_length=20) medical_notes = models.TextField(blank=True) campus = models.CharField(choices=CAMPUS_CHOICES, blank=True, max_length=50)
2. 修改表单的save方法
把表单数据拆分成User字段和Student字段,分别创建User和Student实例:
def save(self): """Create user and student profile.""" data = self.cleaned_data data.pop("password_confirmation") # 移除确认密码字段 # 拆分User模型需要的字段和Student专属字段 user_field_names = ['username', 'email', 'first_name', 'last_name', 'password'] user_data = {key: value for key, value in data.items() if key in user_field_names} student_data = {key: value for key, value in data.items() if key not in user_field_names} # 创建User(create_user会自动加密密码) user = User.objects.create_user(**user_data) # 创建Student并关联到刚创建的User Student.objects.create(user=user, **student_data) return user
3. 表单小修复
你的medical_notes字段定义有误,forms.Textarea是组件而非字段类型,应该改成:
medical_notes = forms.CharField( widget=forms.Textarea(attrs={"class": "form-control", "placeholder": "Medical notes"}), required=False )
另外,clean方法可以优化避免KeyError:
def clean(self): """Verify password confirmation match.""" data = super().clean() password = data.get("password") password_confirmation = data.get("password_confirmation") if password and password_confirmation and password != password_confirmation: raise forms.ValidationError("Passwords do not match.") return data
内容的提问来源于stack exchange,提问作者viktor
相关产品推荐
相关产品推荐

