Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating one Django Form to save two models

I have the regular Django User model and a UserDetails model (OneToOneField with User), which serves as an extension to the User model. (I tried Django 1.5's feature and it was a headache with strangely horrible documentation, so I stuck with the OneToOneField option)

So, in my quest to build a custom registration page that will have a registration form comprised of the User fields and the UserDetails fields, I wondered if there was a way to generate the form automatically (with all of its validations) out of these two related models. I know this works for a form made of one model:

class Meta:
    model = MyModel

But is there anyway to get a similar functionality for a form comprised of two related models?

like image 920
Orca Avatar asked Apr 08 '13 22:04

Orca


People also ask

How can I have multiple models in a single Django ModelForm?

You can just show both forms in the template inside of one <form> html element. Then just process the forms separately in the view. You'll still be able to use form.

How do I save multiple items in Django?

To create multiple records based on a Django model you can use the built-in bulk_create() method.

What is ModelForm Django?

Django Model Form It is a class which is used to create an HTML form by using the Model. It is an efficient way to create a form without writing HTML code. Django automatically does it for us to reduce the application development time.


2 Answers

from django.forms.models import model_to_dict, fields_for_model


class UserDetailsForm(ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        _fields = ('first_name', 'last_name', 'email',)
        _initial = model_to_dict(instance.user, _fields) if instance is not None else {}
        super(UserDetailsForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
        self.fields.update(fields_for_model(User, _fields))

    class Meta:
        model = UserDetails
        exclude = ('user',)

    def save(self, *args, **kwargs):
        u = self.instance.user
        u.first_name = self.cleaned_data['first_name']
        u.last_name = self.cleaned_data['last_name']
        u.email = self.cleaned_data['email']
        u.save()
        profile = super(UserDetailsForm, self).save(*args,**kwargs)
        return profile
like image 194
catherine Avatar answered Sep 22 '22 06:09

catherine


One way you can accomplish this, if you want to keep the ModelForm for User and UserDetails separate would be to return both forms to the front-end, and make sure they are both in the same html form element (i.e. all fields will be returned when data is posted).

This works if User and UserDetails don't have any fields with the same name. To input the data in each ModelForm instance, you use the usual method:

    form_user = UserForm(request.POST, instance=request.user)
    form_user_details = UserDetailsForm(request.POST, instance=request.user.userdetails)
like image 39
YacineAzmi Avatar answered Sep 21 '22 06:09

YacineAzmi