Django Form Component
The Django Form component is used to initialize pages, generate HTML tags, and additionally, it can validate user-submitted data (displaying error messages).
Error Message Display Order:
- Field attribute error messages are displayed first, followed by local hook error messages.
- If field attribute error messages are displayed, local hook error messages will not be displayed.
- If there are global hooks, the global hooks will only start validating after all data has been checked, and the global hook error messages will definitely be displayed.
To use the Form component, you need to import forms first:
from django import forms
Next, we create a My_forms.py
file under the app01
directory:
app01/My_forms.py
from django import forms
from django.core.exceptions import ValidationError
from app01 import models
class EmpForm(forms.Form):
name = forms.CharField(min_length=4, label="Name", error_messages={"min_length": "Too short", "required": "This field cannot be empty!"})
age = forms.IntegerField(label="Age")
salary = forms.DecimalField(label="Salary")
Field Attributes:
- label: Text information before the input field.
- error_message: Custom error messages to be displayed, where the attribute value is a dictionary, and
required
is the key for setting the error message when the field is empty.
app01/views.py
from django.shortcuts import render, HttpResponse
from app01.My_Forms import EmpForm
from app01 import models
from django.core.exceptions import ValidationError
# Create your views here.
def add_emp(request):
if request.method == "GET":
form = EmpForm()
return render(request, "add_emp.html", {"form": form})
else:
form = EmpForm(request.POST)
if form.is_valid(): # Perform data validation
# Validation successful
data = form.cleaned_data # Validated values will be stored in cleaned_data.
data.pop('r_salary')
print(data)
models.Emp.objects.create(**data)
return HttpResponse('ok')
# return render(request, "add_emp.html", {"form": form})
else:
print(form.errors) # Print error messages
clean_errors = form.errors.get("__all__")
print(222, clean_errors)
return render(request, "add_emp.html", {"form": form, "clean_errors": clean_errors})
Add the following rule to the app01/urls.py
file:
path('add_emp/', views.add_emp)
HTML Template:
app01/add_emp.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h3>Add Employee</h3>
{#1. Manually write the HTML page#}
<form action="" method="post">
<p>Name: <input type="text" name="name"></p>
<p>Age: <input type="text" name="age"></p>
<p>Salary: <input type="text" name="salary"></p>
<input type="submit">
</form>
{#2. Implementing using the as_p method of the form object#}
{#<form action="" method="post" novalidate>#}
{# {% csrf_token %}#}
{# {{ form.as_p }}#}
{# <input type="submit">#}
{#</form>#}
{#3. Manually fetching fields of the form object#}
{#<form action="" method="post" novalidate>#}
{# {% csrf_token %}#}
{# <div>#}
{# <label for="id_{{ form.name.name }}">Name</label>#}
{# {{ form.name }} <span>{{ form.name.errors.0 }}</span>#}
{# </div>#}
{# <div>#}
{# <label for="id_{{ form.age.name }}">Age</label>#}
{# {{ form.age }} <span>{{ form.age.errors.0 }}</span>#}
{# </div>#}
{# <div>#}
{# <label for="id_salary">Salary</label>#}
{# {{ form.salary }} <span>{{ form.salary.errors.0 }}</span>#}
{# </div>#}
{# <input type="submit">#}
{#</form>#}
{#4. Displaying all fields using a for loop#}
{#<form action="" method="post" novalidate>#}
{# {% csrf_token %}#}
{# {% for field in form %}#}
{# <div>#}
{# <label for="id_{{ field.name }}">{{ field.label }}</label>#}
{# {{ field }} <span>{{ field.errors.0 }}</span>#}
{# </div>#}
{# {% endfor %}#}
{# <input type="submit">#}
{#</form>#}
</body>
</html>
Local and Global Hooks
Defining the Form class:
app01/My_forms.py
from django import forms
from django.core.exceptions import ValidationError
from app01 import models
class EmpForm(forms.Form):
name = forms.CharField(min_length=5, label="Name", error_messages={"required": "This field cannot be empty!",
"min_length": "The username is too short."})
age = forms.IntegerField(label="Age")
salary = forms.DecimalField(max_digits=5, decimal_places=2, label="Salary")
r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="Please re-enter the salary")
def clean_name(self): # Local hook
val = self.cleaned_data.get("name")
if val.isdigit():
raise ValidationError("The username cannot be purely numeric")
if models.Emp.objects.filter(name=val):
raise ValidationError("Username already exists!")
else:
return val
def clean(self): # Global hook to confirm if the salary inputs match.
val = self.cleaned_data.get("salary")
r_val = self.cleaned_data.get("r_salary")
if val == r_val:
return self.cleaned_data
else:
raise ValidationError("Please confirm if the salaries match.")
# app01/views.py
def add_emp(request):
if request.method == "GET":
form = EmpForm() # Initialize form object
return render(request, "add_emp.html", {"form": form})
else:
form = EmpForm(request.POST) # Pass data to form object
if form.is_valid(): # Perform validation
data = form.cleaned_data
data.pop("r_salary")
models.Emp.objects.create(**data)
return redirect("/index/")
else: # Validation failed
clear_errors = form.errors.get("__all__") # Get global hook error messages
return render(request, "add_emp.html", {"form": form, "clear_errors": clear_errors})
<!-- app01/add_emp.html -->
<form action="" method="post" novalidate>
{% csrf_token %}
<div>
<label for="id_{{ form.name.name }}">Name</label>
{{ form.name }} <span>{{ form.name.errors.0 }}</span>
</div>
<div>
<label for="id_{{ form.age.name }}">Age</label>
{{ form.age }} <span>{{ form.age.errors.0 }}</span>
</div>
<div>
<label for="id_salary">Salary</label>
{{ form.salary }} <span>{{ form.salary.errors.0 }}{{ clear_errors.0 }}</span>
</div>
<div>
<label for="id_r_salary">Please re-enter salary</label>
{{ form.r_salary }} <span>{{ form.r_salary.errors.0 }}{{ clear_errors.0 }}</span>
</div>
<input type="submit">
</form>