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.

Вернуться на верх