djangodjango-formsdjango-templatesdjango-crispy-formsdjango-validation

Django: Crispy Forms Validation Error in Template


I'm using django-crispy-forms for nicely rendered forms. For one of my forms, I had to make some custom adjustments and am now wondering how to properly validation errors that don't belong to a specific field but to the whole form.

Specifically, my form contains a start and end date:

# forms.py 
class PlotForm(forms.Form):
    start_date = forms.DateField(initial=last_month, widget=forms.widgets.DateInput(attrs={'type': 'date'}))
    end_date = forms.DateField(initial=datetime.date.today, widget=forms.widgets.DateInput(attrs={'type': 'date'}))

    def clean(self):
        cleaned_data = super().clean()
        start_date = cleaned_data.get('start_date')
        end_date = cleaned_data.get('end_date')
        if start_date > end_date:
            raise forms.ValidationError("Start date must not be before end date.")
        return start_date

To check that the end date is not before the start date, I use clean(self).

However, the error is never displayed.

<form method="post">
        {% csrf_token %}
        <div class="row">
            <div class="col-6">
                {{ form.start_date|as_crispy_field }}
            </div>
            <div class="col-6">
                {{ form.end_date|as_crispy_field }}
            </div>
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>

I can fix this by adding {{ form.errors }} but that looks really ugly. Is there any simple way to nicely render form-related validation errors with crispy? The field-related errors are shown nicely.


Solution

  • You can use the |as_crispy_errors template filters [readthedocs]:

    <form method="post">
        {% csrf_token %}
        {{ form|as_crispy_errors }}
        <div class="row">
            <div class="col-6">
                {{ form.start_date|as_crispy_field }}
            </div>
            <div class="col-6">
                {{ form.end_date|as_crispy_field }}
            </div>
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>

    This template filter will:

    Renders only form errors the same way as django-crispy-forms.