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