Django: saving multiple modelforms simultaneously (complex case)
Well, it may actually be a simple case but I'm having a tough time figuring it out.
I have two user registration funnels (corporate & everyone else). When a corporate user creates a User instance through my registration form, I would also like them to input secondary forms that create related instances (based on the Website and Organization_Contact models).
I know how to solve this by making additional synchronous or asynchronous requests, but I'd like the user to fill out the three for开发者_如何学JAVAms and submit with one click.
My issue here is that the other two forms rely on a User foreign key as a field. I've made that field "null=True, blank=True" so that I can validate and save the forms without the foreign key, but I ultimately want to add that key to both model instances.
I thought that I could validate the three forms, save the UserForm, and then use a model queryset to return the new User.id (all in one view). I would then add that user_id value to the other two form dictionaries (WebsiteForm and Organization_ContactForm).
It would work as so:
def register_company(request):
if request.method=='POST'
uform=UserCreationForm(request.POST, prefix='user')
sform=SiteForm(request.POST, prefix='site')
oform=OrgForm(request.POST, prefix='site')
if uform.is_valid() and sform.is_valid() and oform.is_valid():
uform.save()
user=User.objects.get(email__iexact=uform.cleaned_data['email'])
uid=unicode(user.id)
#now I'd add uid back into the SiteForm and Orgform dictionaries and then save both instances
Problems: 1) Not sure if I can save a modelform and then return that model instance as a queryset in a single view
2)I say that I'm not sure because I couldn't get passed the problem of trying to pass a variable to the queryset.
The get manager method seems to not accept a variable there. I assume as much because I passed an equivalent hardcoded string and it worked.
Ok, so I was thinking about creating a new manager method (email) which accepted a variable argument (the cleaned email field) and then retrying the process of saving one modelform, retrieving the model id data, and saving the other modelforms.
I also thought that I might be able to handle this issue through a post save signal.
Just general direction here would be really helpful. I need a starting point.
Are these all ModelForm
s?
if request.method=='POST'
uform=UserCreationForm(request.POST, prefix='user')
sform=SiteForm(request.POST, prefix='site')
oform=OrgForm(request.POST, prefix='site')
if uform.is_valid() and sform.is_valid() and oform.is_valid():
# save returns the object
user = uform.save()
# commit = false doesn't save to DB.
site = sform.save(commit=False)
site.user = user
site.save()
org = oform.save(commit=False)
org.user = user
org.save()
Update regarding comments: Why spread this form saving logic around into multiple areas and files (signals, form save) when you can do it in one place?
The code is more readable, and you even save lines of code. Unless it's going to be used globally.
This is how I would do it:
def register_company(request):
uform=UserCreationForm(request.POST or None, prefix='user')
sform=SiteForm(request.POST or None, prefix='site')
oform=OrgForm(request.POST or None, prefix='site')
if request.POST and all((uform.is_valid(), sform.is_valid(), oform.is_valid()):
user = uform.save()
sform.save(user)
oform.save(user)
ruturn ...
class UserCreateionForm(ModelForm):
Meta:
model = User
class SiteForm(ModelForm):
Meta:
model=Site
exclude=['user', ]
def save(self, user, commit=True):
self.instance.user = user
return super(SiteForm, self).save(commit=commit)
精彩评论