Why is my django form validating when I am not calling is_valid
<p>I have a form which actions towards my home view, it contains two buttons, save and cancel. When run on the local dev server (manage.py runserver) this works fine. When I pushed this to production, the cancel button returns form validation errors, despite not calling the is_valid method.</p>

<p>Here is the view:</p>

<pre><code>def home(request):
#uses home.html
if request.method == 'POST':
    #Figure out which button was pressed
    #Cancel Button - Back to home
    if request.POST.get("cancel"):
        #return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
        footer = request
        lineitems = Budget.build(request.user)
        c = {'lineitems': lineitems,
             'footer':footer,}
        return render(request, 'home.html', c)
    #Save button on config.html IncomeForm/Expenses Form
    if request.POST.get("config_save"):
        #ExpensesForm submitted
        if 'expenseName' in request.POST:
            form = ExpensesForm(request.POST)
            if form.is_valid():
                form.save()
            else:
                temp = 'config.html'     
                footer = 'Expense Form Invalid'
                c = {'form':form,
                     'footer':footer,}
                return render(request, temp, c)
        #IncomeForm submitted
        else:
            form = IncomeForm(request.POST)
            if form.is_valid():
                form.save()
            else:
                form = IncomeForm(request.POST)
                temp = 'config.html'     
                footer = 'Form Invalid'
                c = {'form':form,
                     'footer':footer,}
                return render(request, temp, c)
        #Use Budget Class to populate a table in template
        Budget.update_data({'months':12,
                            'user':request.user})
        temp = 'home.html'
        footer = '* Line Modified'
        lineitems = Budget.build(request.user)
        c = {'lineitems': lineitems,
             'footer':footer,}
        return render(request, temp, c)
# if a GET (or any other method) we'll load the budget
else:
    footer = '* Line item modified'
    footer = request
    Budget.update_data({'user': request.user,
                        'months':12})
    lineitems = Budget.build(request.user)
    c = {'lineitems': lineitems,
         'footer':footer,}
    return render(request, 'home.html', c)
</code></pre>

<p>Here is the template:</p>

<pre><code>{% extends "base.html" %}
{% load bootstrap3 %}

{% block title %}
&lt;h1&gt;Add {{ itemtype }}&lt;/h1&gt;
{% endblock %}

{% block content %}
&lt;form action="{% url 'home' %}" method="post"&gt;
{% csrf_token %}
{{ form.as_p }}
&lt;div class="btn-group"&gt;
&lt;input type="submit" name="config_save" value="Save" class="btn btn-primary"/&gt;
&lt;input type="submit" name="cancel" value="Cancel" class="btn btn-default"/&gt;
&lt;/div&gt;
&lt;/form&gt;
{% endblock %}
{% block footer %}
{{ footer }}
{% endblock %}
</code></pre>

<p>EDIT*</p>

<p>I was able to recreate this issue in the dev environment when I replaced</p>

<pre><code>{{ form.as_p }}
</code></pre>

<p>With</p>

<pre><code>{% bootstrap_form form layout='vertical' %}
</code></pre>

<p>But unfortunately neither of these worked when run on the apache/wsgi server.</p>

<p>Here are my forms. Note I also tried removing the class:form-control and it made no difference. I have another form and view that behaves almost identical to this (cancel is handled with an else, form is modelform) that works, the only difference being there are no date fields. To rule out that being the issue I excluded the date fields but still had the same issue.</p>

<pre><code>#Edit form to add/edit Expenses and Bills
class ExpensesForm(forms.ModelForm):
    class Meta:
        model = Items
        exclude = ('skiplst',)
        widgets = {'user': forms.HiddenInput(),
                   'itemType': forms.HiddenInput(),
                   'itemName': forms.TextInput(attrs={'class':'form-control',}),
                   'category': forms.Select(attrs={'class':'form-control',}),
                   'itemAmount': forms.NumberInput(attrs={'class':'form-control',}),
                   'payCycle': forms.Select(attrs={'class':'form-control',}),
                   'itemNote': forms.TextInput(attrs={'class':'form-control',}),
                   'nextDueDate': forms.DateInput(attrs={'name': 'date',
                                                         'class':'form-control'}),
                   'endDate': forms.DateInput(attrs={'name': 'date',
                                                     'class':'form-control'})}

#Edit form to add/edit Income Sources
class IncomeForm(forms.ModelForm):
    class Meta:
        model = Items
        exclude = ('category','skiplst')
        widgets = {'user': forms.HiddenInput(),
                   'itemType': forms.HiddenInput(),
                   'itemName': forms.TextInput(attrs={'class':'form-control',}),
                   'itemAmount': forms.NumberInput(attrs={'class':'form-control',}),
                   'payCycle': forms.Select(attrs={'class':'form-control',}),
                   'itemNote': forms.TextInput(attrs={'class':'form-control',}),
                   'nextDueDate': forms.DateInput(attrs={'name': 'date',
                                                         'class':'form-control'}),
                   'endDate': forms.DateInput(attrs={'name': 'date',
                                                     'class':'form-control'})}
</code></pre>

<p>It looks like (slightly hard to tell as the formatting/indentation is off slightly) when your form is submitting the cancel value, it's submitting <code>Cancel</code>, and you're checking for <code>cancel</code>, so that logic is never executed. </p>

python django python-2.7 django-1.9