I’m trying out a single view function which will display an empty form and also will display a previously filled form for further editing. This is the view I have at present:
def manage_contacts(request):
ContactsFormSet = modelformset_factory(Contact)
if request.method == 'POST':
formset = ContactsFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponseRedirect('/people/')
else:
formset = ContactsFormSet(queryset=Contact.objects.none())
return render_to_response("contact.html", {
"formset": formset,
})
def edit_form(request, item_id):
ContactsFormSet = modelformset_factory(Contact)
if request.method == 'POST':
instance = get_object_or_None(ContactsFormSet, pk=item_id)
formset = Contact(request.POST, instance=instance)
return render_to_response("contact.html", {
"formset": formset,
})
Presently I have two functions: first one shows a new form and the second one for editing existing data. The second function gives an error. I couldn’t get modelformset_factory display data from existing database column. However, the first function works. The snag I face is that I can’t find a way to rewrite both as a single view function. This is what I have in models: https://stackoverflow.com/a/14724113/498309
#urls.py
url(r'^edit/(?P<item_id>\d+)/$', 'app.views.edit_form'),
Update 1
def contact_view(request, item_id=None):
context_data = {}
if item_id:
contact = get_object_or_404(Contact, pk=item_id)
if request.method == 'POST':
forms_are_valid = True
new_form = ContactForm(request.POST, prefix='new')
if new_form.is_valid():
new_form.save()
else:
forms_are_valid = False
context_data['new_form'] = new_form
if item_id:
existing_form = ContactForm(request.POST, instance=contact,
prefix='existing')
if existing_form.is_valid():
existing_form.save()
else:
forms_are_valid = False
context_data['existing_form'] = existing_form
if forms_are_valid:
return HttpResponseRedirect('thanks/')
else:
new_form = ContactForm(prefix='new')
context_data['new_form'] = new_form
if item_id:
existing_form = ContactForm(instance=contact, prefix='existing')
context_data['existing_form'] = existing_form
return render_to_response('contact.html', context_data)
This view does not display the form. But it does not show any errors and it shows just the html template.
I wouldn’t use a modelformset to do what you’re suggesting. Just use two forms in the same view, adding a prefix to differentiate between them –
The contact_id argument in the definition allows you to use the view for both new contacts and existing contacts. Have two url’s point to the same view, one that includes the contact_id and one that doesn’t –
The view checks to see if the item_id is being passed – if is then we know we’re dealing with an existing contact.
I’m afraid I haven’t actually run this code (and it’s slightly longer than I expected), so it may be buggy, however I’ve used this pattern many times before – it does work.
UPDATE
The view passes two forms to the template
new_formandexisting_form. The simplest way to output these forms in the template would be –have a look a the docs on customizing the form template for more info.