I have a page with two forms: a SearchForm and a QuickAddForm. Processing two forms on the same page in Django is not easy, and I'm spent the past two or three days trying to get it to work. I have several unittests that I've been using: a test for each form to make sure it's displaying on the page, a test that a submission of a valid search to the searchform returns the correct results, and three tests for the quickadd form testing that 1) a submission of valid fields results in a new Entry saving to the database; 2) that after an entry is saved, the form redirects to the same page; and 3) that the success message is displayed on that page. For example:
def test_quick_add_form_saves_entry(self):
self.client.post('/editor/', {'quickadd_pre-hw' : 'كلمة'}, follow=True)
self.assertEqual(Entry.objects.count(), 1)
After a lot of work (and helped greatly by the answers and comments on this page: [Proper way to handle multiple forms on one page in Django). I finally got the form working, so that the submitted entry was successfully saved in the database and was redirecting after post. Yay!
Except ... When I open up the page in a browser and try to enter a new Entry, it's clear that it's doing no such thing. You fill out the forms and hit "Save" and ... nothing happens. The page doesn't reload, and the entry isn't added to the database. But the tests (like the one above) testing those very features are passing. (It was at this point that I added the test for the success message, which, at least, has the decency to be failing.) The searchform is working.
I don't know what could possibly be preventing the quickadd form from functioning. Also, I don't understand how the tests could be passing, when the form is not working. What's going on???
Here's the code (Python3, Django1.8 - slightly simplified for clarity):
editor.html
<form id="id_searchform" role="form" method="POST" action="/editor/">
{% csrf_token %}
{{ searchform.as_p }}
<button type="submit" class="btn btn-primary btn-lg"
name="{{searchform.prefix}}">Search</button>
</form>
...
<h1>New entry</h1>
<form id="id_quick_add_form" method="POST" action='/editor/' class="post-form">
{% csrf_token %}
{{ quickaddform.as_p }}
<button type="submit" class="save btn btn-primary"
name='{{quickaddform.prefix}}'>Save</button>
</form>
views.py
def _get_form(request, formcls, prefix):
data = request.POST if prefix in next(iter(request.POST.keys())) else None
return formcls(data, prefix=prefix)
def editor_home_page(request):
if request.method == 'POST':
searchform = _get_form(request, SearchForm, 'searchform_pre')
quickaddform = _get_form(request, QuickAddForm, 'quickadd_pre')
if searchform.is_bound and searchform.is_valid():
query = searchform.cleaned_data['searchterm']
results = Entry.objects.filter(bare_hw__icontains=query)
return render(request, 'dict/editor.html', {
'query' : query,
'results' : results,
'searchform' : searchform,
'quickaddform' : quickaddform,
})
elif quickaddform.is_bound and quickaddform.is_valid():
hw = quickaddform.cleaned_data['hw']
e = Entry.objects.create(hw=hw)
messages.success(request, "Entry %s successfully created." % e.hw)
return redirect('/editor/', {
'searchform': SearchForm(prefix='searchform_pre'),
'quickaddform': QuickAddForm(prefix='quickadd_pre'),
})
else:
return render(request, 'dict/editor.html', {
'searchform': SearchForm(prefix='searchform_pre'),
'quickaddform': QuickAddForm(prefix='quickadd_pre')
})
else:
return render(request, 'dict/editor.html', {
'searchform': SearchForm(prefix='searchform_pre'),
'quickaddform': QuickAddForm(prefix='quickadd_pre')
})
forms.py
class SearchForm(Form):
searchterm = forms.CharField(
max_length=100,
widget=forms.TextInput(attrs={
'placeholder': 'English | العربية',
'class' : 'form-control input-lg',
}),
required=True)
class QuickAddForm(Form):
hw = forms.CharField(
max_length=100,
widget=forms.TextInput(attrs={
'placeholder': 'ex: مَضْروب',
'class' : 'form-control',
}),
required=True)