form errors do not show on the template

Non of my validation errors show, the template page just refreshes if there is something wrong. i placed the validation error code in my forms.py, i don’t know if i am supposed to place it in my views, because nothing works. i also thought django had a default for errors, seems i was wrong.

html

   <form method="post">
        {%csrf_token%}
        <form method="post">{%csrf_token%} {{form.username}} {{form.first_name}} {{form.last_name}} {{form.email}} {{form.phonenumber}} {{form.state}} {{form.next_of_kin}} {{form.dob}} {{form.address}} {{form.password1}} {{form.password2}}
            <li class="btnn"><button type="submit" class="conf">Add</button></li>
        </form>
        {% if form.errors %} {% for field in form %} {% for error in field.errors %}
        <p> {{error}} </p>
        {% endfor %} {% endfor %} {% endif %}

forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class PatientForm(UserCreationForm):
    first_name = forms.CharField(max_length=100, help_text='First Name')
    last_name = forms.CharField(max_length=100, help_text='Last Name')
    address = forms.CharField(max_length=100, help_text='address')
    next_of_kin = forms.CharField(max_length=100, help_text='Next of kin')
    dob = forms.CharField(max_length=100, help_text='Date of birth')
    state = forms.CharField(max_length=100, help_text='State')
    phonenumber = forms.CharField(
        max_length=100, help_text='Enter Phone number')
    email = forms.EmailField(max_length=150, help_text='Email')
    
    

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].widget.attrs.update(
        {'placeholder': ('Username')})
        self.fields['email'].widget.attrs.update(
        {'placeholder': ('Email')})
        self.fields['address'].widget.attrs.update(
            {'placeholder': ('Address')})
        self.fields['phonenumber'].widget.attrs.update(
            {'placeholder': ('Phone number')})
        self.fields['first_name'].widget.attrs.update(
            {'placeholder': ('First name')})
        self.fields['last_name'].widget.attrs.update(
            {'placeholder': ('Last name')})
        
        

        self.fields['password1'].widget.attrs.update({'placeholder': ('Password')})
        self.fields['password2'].widget.attrs.update({'placeholder': ('Repeat password')})
        self.fields['dob'].widget.attrs.update({'placeholder': ('Date of birth')})
        self.fields['state'].widget.attrs.update({'placeholder': ('State')})
        self.fields['next_of_kin'].widget.attrs.update({'placeholder': ('Next of kin')})
        self.fields['first_name'].widget.attrs.update({'class': 'log'})
        self.fields['last_name'].widget.attrs.update({'class': 'log'})
        self.fields['email'].widget.attrs.update({'class': 'log'})
        self.fields['phonenumber'].widget.attrs.update({'class': 'log'})
        self.fields['address'].widget.attrs.update({'class': 'log'})
        self.fields['dob'].widget.attrs.update({'class': 'log'})
        self.fields['state'].widget.attrs.update({'class': 'log'})
        self.fields['next_of_kin'].widget.attrs.update({'class': 'log'})
        self.fields['username'].widget.attrs.update({'class': 'log'})
        self.fields['password1'].widget.attrs.update({'class': 'log swiy'})
        self.fields['password2'].widget.attrs.update({'class': 'log swiy'})

    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'phonenumber',
                  'email', 'password1', 'password2', 'address','dob','state','next_of_kin')
    def clean(self):
        cleaned_data = super(PatientForm, self).clean()
        password = cleaned_data.get('password1')
        password2 = cleaned_data.get('password2')
        if password != password2:
            raise forms.ValidationError('Passwords do not match!')
    
    # Add this to check if the email already exists in your database or not

    def clean_email(self):
        username = self.cleaned_data.get('username')
        email = self.cleaned_data.get('email')
        if email and User.objects.filter(email=email).exclude(username=username).count():
            raise forms.ValidationError('This email is already in use! Try another email.')
        return email
       
     # Add this to check if the username already exists in your database or not     
    def clean_username(self):
        username = self.cleaned_data.get('username')
        email=self.cleaned_data.get('email')
        if username and User.objects.filter(username=username).exclude(email=email).count():
            raise forms.ValidationError('This username has already been taken!')
        return username 

views.py

def addpatient(request):
    form = PatientForm(request.POST)
    if form.is_valid():
        user = form.save()
        user.refresh_from_db()
        user.profile.first_name = form.cleaned_data.get('first_name')
        user.profile.last_name = form.cleaned_data.get('last_name')
        user.profile.email = form.cleaned_data.get('email')
        user.profile.state = form.cleaned_data.get('state')
        user.profile.dob = form.cleaned_data.get('dob')
        user.profile.next_of_kin = form.cleaned_data.get('next_of_kin')
        user.profile.address = form.cleaned_data.get('address')
        user.profile.phonenumber = form.cleaned_data.get('phonenumber')
        user.is_active = True

        user.save()


        username = form.cleaned_data.get('username')
        password = form.cleaned_data.get('password1')
        messages.success(request, 'Account was created for ' + username)
        user = authenticate(username=username, password=password)
        print(username, password, user)
        login(request, user)
        return redirect(f'/dashboard/profile/{user.profile.slug}/{user.pk}')
    else:
        form = PatientForm()
    return render(request, 'core/addpatient.html', {'form': form})

Answer

I think the problem is in your views.py file, specifically, with your check for form valid.

In case of POST, you check if your form is valid, if it is not valid, you create a new form and pass it as contaxt to render method.

if form.is_valid():
   # do if valid form stuff
else:
  # this gets executed every time form is not valid
  # if form is not valid, this will create a new form and return it, not existing form. 
  form = PatientForm()
return render(request, 'core/addpatient.html', {'form': form})

You can solve your problem by removing the else clause and returning the form without creating a new one. Something like this

 form = PatientForm(request.POST)
    if form.is_valid():
        # if stuff
 return render(request, 'core/addpatient.html', {'form': form})

or you can check if method is `POST’ by doing something like this

 def addpatient(request):
    if request.method == "POST"
       form = PatientForm(request.POST)
       if form.is_valid():
        # if  form valid stuff
       return render(request, 'core/addpatient.html', {'form': form})
    
    # this gets executed in case of get method
    form = PatientForm()
    return render(request, 'core/addpatient.html', {'form': form})