2👍
This has been brought up before.
Here’s a blog post with what I think is my favorite solution. The gist is to use two ModelForms, and render them into a single <form>
tag in the template making use of the prefix
kwarg:
http://collingrady.wordpress.com/2008/02/18/editing-multiple-objects-in-django-with-newforms/
Here’s another method which I like a bit less, but is also valid. They use two separate <form>
s on the page, with different actions and two submit buttons:
Proper way to handle multiple forms on one page in Django
This one talks more specifically about Users and UserProfiles:
How to create a UserProfile form in Django with first_name, last_name modifications?
Update
Here is what I ended up with
# models.py
class UserProfile(models.Model):
favorite_color = models.CharField(max_length=30)
user = models.OneToOneField(User)
# forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
# we fill the 'user' value in UserCreateView.form_valid
exclude = ('user',)
# views.py
from django.contrib.auth.forms import UserCreationForm
class UserCreateView(FormView):
# url to redirect to after successful form submission
success_url = reverse_lazy('user_list')
template_name = "userform.html"
def get_context_data(self, *args, **kwargs):
data = super(UserCreateView, self).get_context_data(*args, **kwargs)
data['userform'] = self.get_form(UserCreationForm, 'user')
data['userprofileform'] = self.get_form(UserProfileForm, 'userprofile')
return data
def post(self, request, *args, **kwargs):
forms = dict((
('userform', self.get_form(UserCreationForm, 'user')),
('userprofileform', self.get_form(UserProfileForm, 'userprofile')),
))
if all([f.is_valid() for f in forms.values()]):
return self.form_valid(forms)
else:
return self.form_invalid(forms)
def get_form(self, form_class, prefix):
return form_class(**self.get_form_kwargs(prefix))
def get_form_kwargs(self, prefix):
kwargs = super(UserCreateView, self).get_form_kwargs()
kwargs.update({'prefix': prefix})
return kwargs
def form_valid(self, forms):
user = forms['userform'].save()
userprofile = forms['userprofileform'].save(commit=False)
userprofile.user_id = user.id
userprofile.save()
return HttpResponseRedirect(self.get_success_url())
def get(self, request, *args, **kwargs):
return self.render_to_response(self.get_context_data())
# userform.html
<form action="" method="POST" class="form">
{% csrf_token %}
{{ userform.as_p }}
{{ userprofileform.as_p }}
<button type="submit">Submit</button>
</form>
# urls.py
...
url(r'^create/$', UserCreateView.as_view(), name='user_create'),
...
Source:stackexchange.com