eZ_Harry
eZ_Harry

Reputation: 826

Accessing field from OneToOne field in ModelForm

I am trying to extend Djangos authentication system and have a problem when trying to create the modelForm for it. As you can see below I have referenced the authentication backend via the suggested OneToOnefield however when I am creating the ModelForm if I try to reference the fields such as 'username', 'password' etc. it spits an error saying they are unknown fields. The form I am creating is a registration from. What am I doing wrong here? Cheers

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']

Error -

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

Upvotes: 3

Views: 4492

Answers (2)

ruddra
ruddra

Reputation: 51988

You can't directly access One2One fields like this. You need to first create a object of User and add to One2One relation. You can try like this:

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

Upvotes: 2

doru
doru

Reputation: 9110

A common solution when you need to extend the User model with another model is use two ModelForms: one for User and another for extending model (Student in your case). In the first you access the needed fields of the User model, in the second those of the Student model.

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']

Then, in the view, you work with two forms instead of one. For example:

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()

And in your template you combine both forms in one:

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

Upvotes: 5

Related Questions