2

I am building a very simple form in Django, and want to display form errors in a Bootstrap alert tag. I know how to do this (e.g. Django docs or Django Forms: if not valid, show form with error message or How to render Django form errors not in a UL? ). However, when I do, I am seeing the errors appear twice. It seems like Django's {{ form }} element in the template is displaying the errors in a ul tag by default, in addition to my custom-formatted errors.

What is the best way to avoid this duplication?


In template.html:

<!--Load the file search form from the view-->
<form action="" method="post" id="homepage_filesearch">
    <!--Show any errors from a previous form submission-->
    {% if form.errors %}
        {% for field in form %}
            {% for error in field.errors %}
                <div class="alert alert-danger">
                    <strong>{{ error|escape }}</strong>
                </div>
            {% endfor %}
        {% endfor %}
    {% endif %}

    {{ csrf_input }}
    {{ form }}
    <button class="btn btn-primary" type="submit">Search</span></button>
</form>

In views.py:

from .forms import FileSearchForm
def view(request):
    # Create a form instance and populate it with data from the request
    form = FileSearchForm(request.POST or None)

    # If this is a POST request, we need to process the form data
    if request.method == 'POST':
        if form.is_valid():
            return form.redirect_to_files()

    template = 'template.html'
    context = {'form': form}

    return render(request, template, context)

In forms.py:

class FileSearchForm(forms.Form):
    # Define search field
    search = forms.CharField(label='', max_length=500, required=True,
                             empty_value='Search')

    def clean_search(self):
        # Get the cleaned search data
        search = self.cleaned_data['search']

        # Make sure the search is either a proposal or fileroot
        if some_error_case:
            raise forms.ValidationError('Invalid search term {}. Please provide proposal number or file root.'.format(search))

Result after invalid search: Screenshot of double error

lauren.marietta
  • 2,125
  • 1
  • 11
  • 19

1 Answers1

3

By default, form is rendered with non field errors at top. You can see it at django source code:

def _html_output(self, normal_row, error_row, 
                       row_ender, help_text_html, errors_on_separate_row):
    "Output HTML. Used by as_table(), as_ul(), as_p()."
    # Errors that should be displayed above all fields.
    top_errors = self.non_field_errors()  

You should to elaborate your template to avoid duplicate error messages, may be like Looping over the form’s fields doc's sample:

{{ csrf_input }}
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}   #<-- IDK if you want to render field errors.
        {{ field.label_tag }} {{ field }}
        {% if field.help_text %}
        <p class="help">{{ field.help_text|safe }}</p>
        {% endif %}
    </div>
{% endfor %}

( instead of just {{ form }} }

dani herrera
  • 48,760
  • 8
  • 117
  • 177