0

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)
Community
  • 1
  • 1
larapsodia
  • 387
  • 3
  • 13
  • This code won't work at all; what happens if either of the forms is not valid? – Daniel Roseman Aug 27 '16 at 21:18
  • @DanielRoseman - There's was another "else" block after the "elif", if neither of the forms is bound and valid, it does the same as if it were not POST and just returns the page with empty forms. I took that out when I was pasting it here because I didn't think it was relevant. I edited the question and added it back in. But you say it won't work at all — why won't it work when a form is valid? – larapsodia Aug 28 '16 at 00:47
  • @DanielRoseman Also, the major problem seems to be that it's not even getting to that point. When you press the Save button, it's not running this code. I put some debug lines after `if POST`, `if quickaddform...` and `else`, and the browser didn't hit them. So I think, whatever the mistake is, it must be in the template when I'm calling the form. – larapsodia Aug 28 '16 at 00:54
  • That test isn't testing the response directly that is probably why you didn't catch this in the test. The return value of the post call is the response, put some tests on that to tighten up your test suite. – Dan Sep 20 '16 at 03:57

0 Answers0