My password field and confirm_password field are not being validated as expected except through my view
I am working on a practice project for a P.A.Y.E system. My layout template, home page template, navbar template are located at project level. While my registration template is at app level in my django project. I wrote code in models.py (located at app level) for PAYEAgent class like so:
from django.db import models
from django.contrib.auth.hashers import make_password, check_password
# Create your models here.
class PAYEAgent(models.Model):
payer_id = models.CharField(max_length=100, primary_key=True)
agent_name = models.CharField(max_length=255, unique=True)
agent_rc_num = models.CharField(max_length=50, unique=True)
contact_email = models.EmailField(unique=True)
contact_phone = models.CharField(max_length=20)
address = models.TextField()
agent_password = models.CharField(max_length=128)
registration_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.agent_name
def check_password(self, raw_password):
return check_password(raw_password, self.agent_password)
In my forms.py, the code goes thus:
from django import forms
from . import models
class PAYEAgentForm(forms.ModelForm):
agent_password = forms.CharField(max_length=128, widget=forms.PasswordInput)
confirm_password = forms.CharField(max_length=128, widget=forms.PasswordInput)
class Meta:
model = models.PAYEAgent
fields = ['payer_id', 'agent_name', 'agent_rc_num', 'contact_email', 'contact_phone', 'address', 'agent_password']
def clean_payer_id(self):
payer_id = self.cleaned_data.get('payer_id')
if models.PAYEAgent.objects.filter(payer_id=payer_id).exists():
raise forms.ValidationError("Payer ID already exists.")
return payer_id
def clean_agent_password(self):
password = self.cleaned_data.get('agent_password')
if len(password) < 8:
raise forms.ValidationError("Password must be at least 8 characters long.")
return password
def clean_confirm_password(self):
confirm_password = self.cleaned_data.get('confirm_password')
if len(confirm_password) < 8:
raise forms.ValidationError("Confirm Password must be at least 8 characters long.")
return confirm_password
def clean(self):
cleaned_data = super().clean()
password = cleaned_data.get("agent_password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
self.add_error('confirm_password', "Passwords do not match.")
return cleaned_data
Basically, my code runs and so far seems to work fine except for a bug I discovered which is the validation of the agent_password field (comparing it to the confirm_password field). The form gets submitted without doing the comparison. Also the validation via the field clean methods for agent_password field and confirm_password field respectively do not seem to work either (clean_agent_password() is meant to check if the length of the password is less than 8; same for clean_confirm_password()). The only way I at least solved the comparison bug was in my view in views.py:
from django.contrib.auth.hashers import make_password
from django.shortcuts import render, redirect
from .forms import PAYEAgentForm
def registration(request):
form = None # Placeholder for form instance, e.g., PAYEAgentForm()
if request.method == 'POST':
form = PAYEAgentForm(request.POST)
if form.is_valid():
if form.cleaned_data['agent_password'] == form.cleaned_data['confirm_password']:
agent = form.save(commit=False) # Adjust as necessary to handle password hashing if needed
agent.agent_password = make_password(form.cleaned_data['agent_password'])
agent.save()
return redirect('success') # Redirect to a success page after registration
else:
form.add_error('confirm_password', "Passwords do not match.")
else:
form = PAYEAgentForm()
return render(request, 'registration.html', {'form': form})
def success(request):
return render(request, 'success.html')
Validation in the view function does create tight coupling doesn't it? And based on the bits I have read in documentation and other sources I found via google, it seems like I should not have to do that in the view. Once form.is_valid() is called in my code and it returns False, the errors should have been shown in my template. The validation to keep in mind here is the comparison of both agent_password and confirm_password as well the individual validation of either of them. I do not know what I have done wrong. I would deeply appreciate the help.
I did not bother template code because I feel the error is somewhere in the code I have shared but I am yet to figure it out.