如何在 2022 年向 ModelForm 呈现错误或验证消息

How to render error or validation messages to ModelForm in 2022

我花了几个小时在互联网上进行研究,尤其是官方 Django 文档,但我仍然不清楚哪个是 2022 年的最佳选择(因为我在 SO 上阅读的几乎所有问题都 > 6 岁) 对于脆皮好还是不好吃,众说纷纭

脆皮仍然是推荐的选择吗?

我如何(以及最推荐的方法)获取典型的验证错误消息?

喜欢:“this field is mandatory”或“this input accepts numbers only”?我见过一些使用这些默认消息的 Django 页面,但我不知道如何在我的 ModelForm 字段中显示它们。

假设我有以下模型:

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)

对于 Project 模型,我有以下 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__'

视图,当我尝试创建一个新对象时 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部分:

<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>

我看到了像 this 这样的解决方案,但问题是我的表单字段分布在不同的手风琴上,我不能使用像 {% if form.errors %} 这样的东西,我需要为每个字段提供更具体的东西.

首先像这样更新你的观点


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)

您可以像这样为每个字段指定错误

{% if form.field_name.errors %}
  {{ form.field_name.errors }}
{% endif %}