0

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 class="card h-100">
    <div class="card-header project-page-header">
        <h3>Create A New Project</h3>
    </div>
    <div class="card-body px-0 new-project-card-body">
        <div class="cardItem">
            <div class="row">
                <div class="col">
                    <div class="row">
                        <div class="tab-pane fade show active" id="general">
                            <form id="newProjectForm" method="POST" action="new_project">
                                {% csrf_token %}
                                <div class="accordion accordion-flush" id="accordionGeneral">
                                    <div class="accordion-item">
                                        <h2 class="accordion-header" id="general-headingOne">
                                            <button class="accordion-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" class="accordion-collapse collapse show" aria-labelledby="general-headingOne" data-bs-parent="#accordionGeneral">
                                            <div class="accordion-body">
                                                <div class="row">
                                                    <div class="col-5">
                                                        <ul class="list-unstyled">
                                                            <li class="mt-3">
                                                                <div class="row">
                                                                    <div class="col-sm ph-tabs-field-label">
                                                                        Project Name
                                                                    </div>
                                                                    <div class="col-sm">
                                                                        <input type="text" name="project_name" class="form-control" aria-label="Project Name">
                                                                    </div>
                                                                </div>
                                                            </li>
                                                            <li class="mt-3">
                                                                <div class="row">
                                                                    <div class="col-sm ph-tabs-field-label">
                                                                        Status
                                                                    </div>
                                                                    <div class="col-sm">
                                                                        <select name="status" class="selectpicker show-tick w-100"  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 class="mt-3">
                                                                <div class="row">
                                                                    <div class="col-sm ph-tabs-field-label">
                                                                        Creation Date
                                                                    </div>
                                                                    <div class="col-sm">
                                                                        <input type="text" name="creation_date" class="form-control">
                                                                    </div>
                                                                </div>
                                                            </li>
                                                            <li class="mt-3">
                                                                <div class="row">
                                                                    <div class="col-sm ph-tabs-field-label">
                                                                        Project Code
                                                                    </div>
                                                                    <div class="col-sm">
                                                                        <input type="text" name="project_code" class="form-control">
                                                                    </div>
                                                                </div>
                                                            </li>
                                                        </ul>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="accordion-item">
                                        <h2 class="accordion-header" id="general-headingThree">
                                            <button class="accordion-button collapsed" 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" class="accordion-collapse collapse" aria-labelledby="general-headingThree" data-bs-parent="#accordionGeneral">
                                            <div class="accordion-body"><textarea name="notes" class="form-control" rows="7"></textarea></div>
                                        </div>
                                    </div>
                                    <button type="submit" id="projectEditBtn" form="newProjectForm" class="btn btn-info rounded-0">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.

Cheknov
  • 1,892
  • 6
  • 28
  • 55

1 Answers1

0

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 %}
Ankit Tiwari
  • 4,438
  • 4
  • 14
  • 41
  • I tried your code but it did not work. `print(form.errors)` returns this in the console: `
    • project_name
      • This field is required.
    ` but with: `{% if form.project_name.errors %} {{ form.project_name.errors }} {% endif %}` nothing is printed.
    – Cheknov Jan 06 '22 at 03:37
  • Hello @Cheknov because you're not passing your invalid form in context properly – Ankit Tiwari Jan 06 '22 at 03:40
  • Hello @Cheknov check I've edited my answer – Ankit Tiwari Jan 06 '22 at 03:45