Django CreateView通过3个关联模型的ModelForm无法创建新用户问题咨询
我在Django项目中创建了多个模型,其中包含一个扩展的User模型。最初我通过UserCreationForm和基于ModelForm的EmployeeForm两个表单,使用函数视图完成数据验证和用户创建,流程完全正常。直到我引入第三个表单并改用CreateView实现后,就出现了数据不保存、也不跳转的问题。
模型代码
class Employee(models.Model): SENIOR = 'Sr' JUNIOR = 'Jr' FIRST = 'I' SECOND = 'II' THIRD = 'III' GENERATIONAL_SUFFIX = [ (SENIOR, 'Senior'), (JUNIOR, 'Junior'), (FIRST, 'First'), (SECOND, 'Second'), (THIRD, 'Third'), ] MALE = 'male' FEMALE = 'female' OTHER = 'other' SEX = [ (MALE, 'Male'), (FEMALE, 'Female'), (OTHER, 'Other'), ] user = models.OneToOneField(User, on_delete=models.CASCADE) phone_regex = RegexValidator(regex=r'^\d{11}$', message="Phone number must be entered in the format: '09151234567'.") phone_number = models.CharField(validators=[phone_regex], max_length=11, blank=True) middle_name = models.CharField(max_length=20, blank=True) sex = models.CharField(max_length=6, choices=SEX, blank=True) suffix = models.CharField(max_length=3, choices=GENERATIONAL_SUFFIX, blank=True) birthday = models.DateField(null=True, blank=True) hire_date = models.DateField(null=True, blank=True) image = models.ImageField(blank=True, default='blank_profile_picture.jpg') slug = models.SlugField(max_length=60, blank=True, null=True) updated = models.DateTimeField(auto_now=True) @property def get_full_name(self): first_name = self.user.first_name middle_name = self.middle_name last_name = self.user.last_name if middle_name is None: full_name = f'{first_name} {last_name}' return full_name else: full_name = f'{first_name} {middle_name} {last_name}' return full_name def save(self, *args, **kwargs): self.slug = slugify(self.get_full_name) super().save(*args, **kwargs) def __str__(self): return self.get_full_name class EmployeePosition(models.Model): employee = models.ForeignKey(Employee, on_delete=models.CASCADE) position = models.ForeignKey(Position, on_delete=models.CASCADE) position_change_reason = models.ForeignKey(PositionChangeReason, on_delete=models.CASCADE, default='Hired As') effective_date = models.DateField() def __str__(self): return str(self.position)
表单代码
class EmployeeRegistrationForm(UserCreationForm): email = forms.EmailField(required=True, widget=forms.EmailInput(attrs={'class': 'form-control mb-2', 'placeholder': 'juandelacruz@email.com'})) first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': 'Juan'})) last_name = forms.CharField( widget=forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': 'Dela Cruz'})) password1 = None password2 = None class Meta: model = User fields = ['email', 'first_name', 'last_name'] def clean(self): password = User.objects.make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789') self.cleaned_data['password1'] = password self.cleaned_data['password2'] = password return super().clean() def save(self, commit=True): user = super().save(commit=False) user.email = self.cleaned_data['email'] user.first_name = self.cleaned_data['first_name'] user.last_name = self.cleaned_data['last_name'] user.is_active = False if len(user.first_name.split()) and len(user.last_name.split()) > 1: username = f'{"".join(user.first_name.split()[:2])}.{"".join(user.last_name.split())}' elif len(user.first_name.split()) > 1: username = f'{"".join(user.first_name.split()[:2])}.{user.last_name}' elif len(user.last_name.split()) > 1: username = f'{user.first_name}.{"".join(user.last_name.split())}' else: username = f'{user.first_name}.{user.last_name}' username = username.lower() user.username = username user.set_password(self.cleaned_data['password1']) if commit: user.save() return user class EmployeeForm(forms.ModelForm): class Meta: model = Employee fields = ['phone_number', 'middle_name', 'sex', 'suffix', 'birthday', 'hire_date'] widgets = { 'phone_number': forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': '09151234567'}), 'middle_name': forms.TextInput(attrs={'class': 'form-control mb-2', 'placeholder': 'Rodriguez'}), 'suffix': forms.Select(attrs={'class': 'form-select mb-2'}), 'sex': forms.Select(attrs={'class': 'form-select mb-2'}), 'birthday': forms.DateInput(attrs={'type': 'date', 'class': 'form-control mb-2'}, format='%m/%d/%Y'), 'hire_date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control mb-2'}, format='%m/%d/%Y'), } class EmployeePositionForm(forms.ModelForm): position_change_reason = forms.Select() effective_date = forms.DateField() class Meta: model = EmployeePosition fields = ['employee', 'position', 'position_change_reason', 'effective_date'] widgets = { 'position': forms.Select(attrs={'class': 'form-select mb-2', 'id': 'position'}), } def check_position_change_reason(self): position_change_reason = self.cleaned_data['position_change_reason'] if not position_change_reason: position_change_reason = EmployeePosition.position_change_reason.get_default() return position_change_reason def check_effective_date(self): effective_date = self.cleaned_data['effective_date'] if not effective_date: effective_date = Employee.hire_date return effective_date def save(self, commit=True): position = super().save(commit=False) position.position_change_reason = self.cleaned_data['position_change_reason'] position.effective_date = self.cleaned_data['effective_date'] position.position = self.cleaned_data['position'] return position
我在第三个表单中尝试为两个字段设置了默认值,用于处理用户未输入的场景。
视图代码
class RegisterEmployeeView(LoginRequiredMixin, CreateView): model = User form_class = EmployeeRegistrationForm profile_form_class = EmployeeForm position_form_class = EmployeePositionForm template_name = 'accounts/register.html' success_url = '/' def get(self, request, *args, **kwargs): form = self.form_class(**self.get_form_kwargs()) profile_form = self.profile_form_class(prefix='profile_form') position_form = self.position_form_class(prefix='position_form') return render(request, self.template_name, {'form': form, 'profile_form': profile_form, 'position_form': position_form}) def post(self, request, *args, **kwargs): form = self.form_class(request.POST) profile_form = self.profile_form_class(request.POST) position_form = self.position_form_class(request.POST) if form.is_valid() and profile_form.is_valid() and position_form.is_valid(): user = form.save() profile = profile_form.save(commit=False) position_profile = position_form.save(commit=False) profile.user = user position_profile.employee = profile.employee profile.save() position_profile.save() messages.success(self.request, f'{User.first_name} {User.last_name} was registered successfully.') return HttpResponseRedirect(self.get_success_url()) else: context = {'form': form, 'profile_form': profile_form, 'position_form': position_form} return render(request, self.template_name, context)
我查阅了大量同类问题的资料仍未解决,已知该现象通常是验证错误导致,但我作为Django初学者仍无法定位问题。
更新
我遵循建议对表单做了子类化以便后续复用,请问如下的子类化方式是否正确?
class EmployeeInitialPositionForm(EmployeePositionForm): class Meta: model = EmployeePosition exclude = ['employee']
内容的提问来源于stack exchange,提问作者John Todorovic
相关产品推荐
相关产品推荐

