How to pre-fill a ModelForm with existing data

Hi everyone!

The expected Django behavior (filling the form with the passed instance data) didn’t work in this case, here is my code:

  1. The UpdateView:
class ClientProfile(LoginRequiredMixin, UpdateView):
    model = get_user_model()
    form_class = ProfileForm
    template_name = 'client_profile.html'
    
    # def get_initial(self):
    #     initial = super().get_initial()
    #     for field_name in self.object._meta.get_fields():
    #         if hasattr(self.object, field_name.name):
    #             initial[field_name.name] = getattr(self.object, field_name.name)
    #     return initial

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['profile_includes_instance'] = self.object.profile_includes
        return kwargs

It works only when using the get_initial method. However, I know from the documentation that passing the instance (automatically done with UpdateView) will prefill the rendered form perfectly.

  1. The ModelForm:
class ProfileForm(forms.ModelForm):
    profile_includes_form = ProfileIncludesForm()

    # include the profile_include form
    def __init__(self, *args, **kwargs):
        # to get previous data if exist else None
        profile_includes_instance = kwargs.pop('profile_includes_instance', None)
        super().__init__(*args, **kwargs)
        self.profile_includes_form = ProfileIncludesForm(
            *args,
            instance=profile_includes_instance,
        )

    def is_valid(self):
        return super().is_valid() and self.profile_includes_form.is_valid()
    
    def save(self, commit=True):
        client = super().save(commit=commit)
        profile_includes_form = self.profile_includes_form.save(commit=False)
        profile_includes_form.client = client
        if commit:
            profile_includes_form.save()
        return client

    class Meta:
        # ...

I appreciate every help you provide, thank you in advance

Where is your Meta code?

ProfileIncludesForm – Where is this code?

I thought it 's not that important to show it, however, here is it:

  1. the Meta code:
    class Meta:
        model = get_user_model()
        exclude = ['username', 'payment_method', 'is_seller', 'is_verified', 'password', 'date_joined']
        widgets = {
            'first_name': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'Your first name'}),
            'last_name': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'Your family name'}),
            'gender': forms.RadioSelect(attrs={}),
            'birthday': forms.DateInput(attrs={'type': 'date', 'class': 'input-field small-width-input'}),
            'wilaya': forms.Select(
                attrs={'class': 'input-field'},
                choices=AlgerianWilayasDB.objects.values_list('wilaya_id', 'wilaya_name')
            ),
            'city': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'Your city where you live'}),
            'street': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'Your street name and number'}),
            'apt': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'Number of home or workplace or...'}),
            'postal_code': forms.TextInput(attrs={'class': 'input-field', 'placeholder': 'ex: 16014'}),
            'phone': forms.TextInput(attrs={'class': 'input-field small-width-input', 'placeholder': 'ex: 0512345678', 'pattern': r'^0[567]\d{8}$'}),
        }

        # there are also some custom validation methods
  1. the ProfileInclude code:
class ProfileIncludesForm(forms.ModelForm):
    label = 'Profile includes'
    class Meta:
        model = ProfileIncludes
        exclude = ['client']
        widgets = {
            'gender': forms.CheckboxInput(attrs={'checked': ''}),
            'birthday': forms.CheckboxInput(attrs={'checked': ''}),
            'join_date': forms.CheckboxInput(attrs={'checked': ''}),
            'favorites': forms.CheckboxInput(attrs={'checked': ''})
        }


Side note: Something here that may or may not be directly relevent to this specific issue, is that whenever you’re handing data from multiple forms on the same page, you want to use the prefix attribute on the form to ensure the post data is directed to the right form instance.

Hi Ken!
Yep … that’s a good note, thank you ^^

Are all these fields:

Fields of the user model? That’s the only way they’re going to be applied to this form.

If you want additional fields on the form that aren’t part of the model, they need to be defined on the form. (ModelForms only generate fields for the fields in the model, and the widgets dict in Meta only apply to those generated fields.)

@KenWhitesell
Regarding the fields, I changed the main user model from User to my custom Client model, and yes you’re right, I did define the profile_includes_form = ProfileIncludesForm() at the top of the ModelForm (is that what you mean?), however, my main issue here is that the main ModelFom (ProfileForm) didn’t prefill the existing data of the self.object, and I don’t know why. any help would be appreciated sir, thank you so much

What you have done here:

Is create a class-variable containing a blank instance of the form. This isn’t going to work the way you’re thinking it’s going to work.

A form is not a field.

:bulb: The light has gone on - now I think I understand what you’re trying to do.

Unfortunately, my response to this is “don’t do this”. Work with the two forms as two separate forms - do not try to integrate them like this. (This is an approach that I wouldn’t ever try to do.)

There’s a lot of “metaprogramming magic” that occurs within the Django Form class, and even more with ModelForms.

I have a philosophy that has served me well for a long time: “Don’t fight the framework.” Do things the way the framework expects you to do them, don’t try to twist it to make it fit your mental model - change your mental model instead.

See the post at How to handle forms that don't map easily to a single model for some ideas.

There are other threads in the forum itself addressing this type of situation.

1 Like

Okay @KenWhitesell, I understand what you want to say, and I like your mentioned philosophy. I will definitely take a look at that post

Thank you so muck for you time sir ^^