djangodjango-modelsdjango-forms

Django Unknown fields FieldError in forms.py with nested User model


Okay so this is a Django project I'm starting, and I have a User model in models.py. It has nested models, the 'contact' model and the 'personal' model. I want to create a form in Django.

models.py

class User(models.Model):
    """
    Model representing a User with field groups
    """

    class ContactInfo(models.Model):
        email = models.EmailField(
            max_length=120,
            validators=[EmailValidator()],
            unique=True,
            verbose_name="Contact Email"
        )
        phone = models.CharField(
            max_length=10,
            blank=True,
            null=True,
            verbose_name="Phone Number"
        )
        address = models.CharField(
            max_length=100,
            validators=[MinLengthValidator(5)],
            verbose_name="Address"
        )
        suite = models.CharField(
            max_length=20,
            validators=[MinLengthValidator(0)],
            verbose_name="Suite"
        )
        city = models.CharField(
            max_length=50,
            validators=[MinLengthValidator(3)],
            verbose_name="City"
        )
        state = models.CharField(
            max_length=2,
            validators=[MinLengthValidator(2)],
            verbose_name="State"
        )
        zip_code = models.CharField(
            max_length=5,
            validators=[MinLengthValidator(5)],
            verbose_name="Zip Code"
        )

    class PersonalInfo(models.Model):
        first_name = models.CharField(
            max_length=40,
            validators=[MinLengthValidator(2)],
            verbose_name="First Name"
        )
        last_name = models.CharField(
            max_length=40,
            validators=[MinLengthValidator(2)],
            verbose_name="Last Name"
        )

        company = models.CharField(
            max_length=100,
            validators=[MinLengthValidator(5)],
            verbose_name="Company Name"
        )
    contact = models.OneToOneField(
        ContactInfo,
        on_delete=models.CASCADE,
        related_name='user_contact'
    )
    personal = models.OneToOneField(
        PersonalInfo,
        on_delete=models.CASCADE,
        related_name='user_personal'
    )

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.personal.first_name} {self.personal.last_name}"

forms.py

from django import forms
from .models import User, Request


class UserForm(forms.ModelForm):
    """
    Form for users
    """

    class Meta:
        model = User
        fields = (
            'personal.first_name',
            'personal.last_name',
            'personal.company',
            'contact.email',
            'contact.phone',
            'contact.address',
            'contact.suite',
            'contact.city',
            'contact.state',
            'contact.zip_code',
        )

    def save(self, commit=True):
        user = super().save(commit=False)

        contact_info, _ = User.ContactInfo.objects.get_or_create(
            email=self.cleaned_data['contact.email'],
            phone=self.cleaned_data['contact.phone'],
            address=self.cleaned_data['contact.address'],
            suite=self.cleaned_data['contact.suite'],
            city=self.cleaned_data['contact.city'],
            state=self.cleaned_data['contact.state'],
            zip_code=self.cleaned_data['contact.zip_code']
            
        )

        personal_info, _ = User.PersonalInfo.objects.get_or_create(
            first_name=self.cleaned_data['personal.first_name'],
            last_name=self.cleaned_data['personal.last_name'],
            company=self.cleaned_data['personal.company']
        )
        
        user.contact = contact_info
        user.personal = personal_info


        if commit:
            user.save()

        return user

I am getting the following error.


  File "/develop/repos/template_py/django_template/django_template/urls.py", line 21, in <module>
    from django_template_app import views
  File "/develop/repos/template_py/django_template/django_template_app/views.py", line 10, in <module>
    from .forms import UserForm, RequestForm
  File "/develop/repos/template_py/django_template/django_template_app/forms.py", line 5, in <module>
    class UserForm(forms.ModelForm):
  File "/home/matt/.local/share/virtualenvs/template_py-7Odno36H/lib/python3.12/site-packages/django/forms/models.py", line 334, in __new__
    raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (contact.city, contact.state, contact.email, personal.company, contact.suite, contact.address, personal.last_name, personal.first_name, contact.zip_code, contact.phone) specified for User

Solution

  • class ContactInfoForm(forms.ModelForm):
    
        class Meta:
            model = ContactInfo
            fields = ['email', 'phone', 'address', 'suite', 'city', 'state', 'zip_code']
    
    
    class PersonalInfoForm(forms.ModelForm):
        
        class Meta:
            model = PersonalInfo
            fields = ['first_name', 'last_name', 'company']
    
    
    class UserForm(forms.ModelForm):
        
        contact_form = ContactInfoForm(prefix="contact")
        personal_form = PersonalInfoForm(prefix="personal")
    
        class Meta:
            model = User
            fields = []
    
        def __init__(self, *args, **kwargs):
            contact_data = kwargs.pop('contact_data', None)
            personal_data = kwargs.pop('personal_data', None)
            super().__init__(*args, **kwargs)
            
            self.contact_form = ContactInfoForm(contact_data, prefix="contact")
            self.personal_form = PersonalInfoForm(personal_data, prefix="personal")
    
        def is_valid(self):
            
            return super().is_valid() and self.contact_form.is_valid() and self.personal_form.is_valid()
    
        def save(self, commit=True):
            
            user = super().save(commit=False)
    
            contact_info = self.contact_form.save(commit=commit)
            personal_info = self.personal_form.save(commit=commit)
    
            user.contact = contact_info
            user.personal = personal_info
    
            if commit:
                user.save()
    
            return user
    

    Would you try this?