Home > Software design >  How to render error or validation messages to ModelForm in 2022
How to render error or validation messages to ModelForm in 2022

Time:01-06

I've spent several hours researching on the internet, especially the official Django documentation, but still it is not clear to me which is the best option in 2022 (since almost all questions I read on SO are > 6 yo) and there are diverse opinions on whether crispy forms is better or not.

Is still crispy forms a recommended option?

How can I (and what is the most recommended way to) get the typical validation error messages?

Like: "this field is mandatory" or "this input accepts numbers only"? I've seen some Django pages using those default messages but I don't know how to show them in my ModelForm fields.

Lets say I have the following model:

class Project(models.Model):
    project_name = models.CharField(max_length=250, null=False, blank=False)
    status = models.CharField(
        max_length=250, 
        null=True, 
        blank=True, 
        default=PROJECT_STATUS_DEFAULT,
        choices=PROJECT_STATUS,
    )
    creation_date = models.DateField(max_length=250, null=False, blank=False)
    project_code = models.IntegerField(null=True, blank=True)
    notes = models.CharField(max_length=250, null=True, blank=True)

And for the Project model I have the following ModelForm:

class CreateNewProjectForm(ModelForm):
    creation_date = forms.DateField(widget=forms.DateInput(format = '%d/%m/%Y'), input_formats=settings.DATE_INPUT_FORMATS) #UK Date format
    class Meta:
        model = Project
        fields = '__all__'

The view, when I try to create a new object Project:

def add_new_project(request):
    context = {}
    if request.method == 'POST':
        form = CreateNewProjectForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('project_page')
        else:
            print (form.errors)
            form = CreateNewProjectForm()
        context['form'] = form
    return render(request, 'new_project.html', context)

HTML part:

<div >
    <div >
        <h3>Create A New Project</h3>
    </div>
    <div >
        <div >
            <div >
                <div >
                    <div >
                        <div  id="general">
                            <form id="newProjectForm" method="POST" action="new_project">
                                {% csrf_token %}
                                <div  id="accordionGeneral">
                                    <div >
                                        <h2  id="general-headingOne">
                                            <button  type="button" data-bs-toggle="collapse" data-bs-target="#general-collapseOne" aria-expanded="false" aria-controls="general-collapseOne">
                                            Details
                                            </button>
                                        </h2>
                                        <div id="general-collapseOne"  aria-labelledby="general-headingOne" data-bs-parent="#accordionGeneral">
                                            <div >
                                                <div >
                                                    <div >
                                                        <ul >
                                                            <li >
                                                                <div >
                                                                    <div >
                                                                        Project Name
                                                                    </div>
                                                                    <div >
                                                                        <input type="text" name="project_name"  aria-label="Project Name">
                                                                    </div>
                                                                </div>
                                                            </li>
                                                            <li >
                                                                <div >
                                                                    <div >
                                                                        Status
                                                                    </div>
                                                                    <div >
                                                                        <select name="status"   aria-label="Status">
                                                                        {% for status in project_status %}
                                                                            {% if forloop.first %} 
                                                                            <option value="{{ status.id }}" selected>{{ status.text }}</option> 
                                                                            {% else %}
                                                                            <option value="{{ status.id }}">{{ status.text }}</option>
                                                                            {% endif %}
                                                                        {% endfor %}
                                                                        </select>
                                                                    </div>
                                                                </div>
                                                            </li>
                                                            <li >
                                                                <div >
                                                                    <div >
                                                                        Creation Date
                                                                    </div>
                                                                    <div >
                                                                        <input type="text" name="creation_date" >
                                                                    </div>
                                                                </div>
                                                            </li>
                                                            <li >
                                                                <div >
                                                                    <div >
                                                                        Project Code
                                                                    </div>
                                                                    <div >
                                                                        <input type="text" name="project_code" >
                                                                    </div>
                                                                </div>
                                                            </li>
                                                        </ul>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div >
                                        <h2  id="general-headingThree">
                                            <button  type="button" data-bs-toggle="collapse" data-bs-target="#general-collapseThree" aria-expanded="false" aria-controls="general-collapseThree">
                                            Note
                                            </button>
                                        </h2>
                                        <div id="general-collapseThree"  aria-labelledby="general-headingThree" data-bs-parent="#accordionGeneral">
                                            <div ><textarea name="notes"  rows="7"></textarea></div>
                                        </div>
                                    </div>
                                    <button type="submit" id="projectEditBtn" form="newProjectForm" >Save</button>
                                </div>
                            </form>
                        </div>
                    </div>        
                </div>
            </div>
        </div>
    </div>
</div>

I saw solutions like this, but the problem is that my form fields are spread over different accordions, I can't use something like {% if form.errors %}, I need something more specific for each field.

CodePudding user response:

First update your views like this


def add_new_project(request):
    context = {}
    if request.method == 'POST':
        form = CreateNewProjectForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('project_page')
        else:
            print (form.errors)
            context['form'] = form
            return render(request, 'new_project.html', context)
    context['form'] = CreateNewProjectForm()
    return render(request, 'new_project.html', context)

You can specify error for each field like this

{% if form.field_name.errors %}
  {{ form.field_name.errors }}
{% endif %}
  •  Tags:  
  • Related