从ModelForm中的OneToOne字段访问字段

3

我想扩展Django的认证系统,在创建其modelForm时遇到了问题。如下所示,我通过建议的OneToOneField引用了认证后端,但是,当我创建ModelForm时,如果我尝试引用像“用户名”、“密码”等字段,它会抛出一个错误,说这些字段是未知的。我正在创建的表单是一张注册表格。我在这里做错了什么?谢谢。

Model:

class StudentModel(models.Model):
    user = models.OneToOneField(User, unique=True)
    birth_date = models.DateField()
    contact_number = models.IntegerField()
    referral = models.CharField(max_length=100, choices=referral_choices)

ModelForm -

from django import forms
from opus_login.models import StudentModel, EmployerModel

class StudentForm(forms.ModelForm):

    class Meta:
        model = StudentModel
        fields = ['username', 'first_name']

错误 -

django.core.exceptions.FieldError: Unknown field(s) (username, first_name) specified for StudentModel

这些字段在用户模型上,你不只需要将你的模型表单与该模型匹配吗?birth_date和其他字段不能为null,因此仅显示这两个字段本身也无法工作。 - Sayse
ModelForm只能访问模型的字段。https://dev59.com/JF4c5IYBdhLWcg3wgqr2 - Aviah Laor
2个回答

5

在需要通过另一个模型扩展 User 模型时,常见的解决方案是使用两个 ModelForm:一个用于 User,另一个用于扩展模型(在你的情况下为 Student)。在第一个表单中,您可以访问 User 模型的所需字段,在第二个表单中则可访问 Student 模型的所需字段。

class UserForm(forms.ModelForm):
    password = forms.CharField(label='Password',widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repeat password',widget=forms.PasswordInput)

    class Meta:
    model = User
    fields = ('username', 'first_name')

    def clean_password2(self):
        .......
        return password2

class StudentForm(forms.ModelForm):
    class Meta:
        model = StudentModel
        fields = ['birthdate', 'contact_number']

然后,在视图中,您需要使用两个表单而不是一个。例如:

def register(request):
    if request.method == 'POST':
        user_form = UserForm(request.POST)
        student_form = StudentForm(request.POST)
        if user_form.is_valid() and student_form.is_valid():
            user_form.save()
            student_form.save()

在您的模板中,您将两个表单组合在一起:

<form action="." method="post">
  {{ user_form.as_p }}
  {{ student_form.as_p }}
  {% csrf_token %}
  <p><input type="submit" value="Register"></p>
</form>

你好,我一直在尝试使用你的方法,因为在我看来这是最合理的。然而我遇到了一个问题,就是无法修改用户模型,比如说我计划为密码字段添加clean()函数,但是用这个方法是不可能的。你有什么建议吗? - eZ_Harry
@eZ_Harry 我已经编辑了答案。你不必修改“User”模型,因为它有一个密码字段。 - doru

2
您不能直接访问One2One字段。您需要先创建一个User对象并将其添加到One2One关系中。您可以尝试以下方式:
from django import forms
from opus_login.models import StudentModel, EmployerModel

class StudentForm(forms.ModelForm):
    username = forms.CharField()
    first_name = forms.CharField()

    class Meta:
        model = StudentModel
        fields = ['__all__']

    def save(self, **kwargs):
        student = super().save(commit=False)
        user = User.objects.create(username=self.cleaned_data['username'], first_name=self.cleaned_data['first_name'])
        user.set_password(self.cleaned_data['password']) #if there is a password field
        student.user = user
        student.save(commit=True)
        return student

我猜当首先调用super()。save()方法时,由于它是一个ModelForm并且这些字段不在模型中,因此save()方法会报错。 - zaidfazil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接