Django - Register User with Confirm Password validation/error message on Bootstrap form

I am trying to create a Register User form using Django 6 and Bootstrap 5. The form displays field level validation/error messages. However, I am not sure how to include the Confirm Password field (with error/validation messages), since this field is not a part of the model but is needed to ensure Password is correct before saving the form. Below is the source. Is there any other method/approach of achieving the same output (i.e. field level error/validation messages on the html form) in a better and more efficient way? Thanks to the code by Francisco Alejandro Rojas

models.py

class UserMaster(models.Model):
    username = models.CharField(max_length=50, unique=True)
    password = models.CharField(max_length=15)
    
    def __str__(self):
        return self.username

forms.py

class UserMasterForm(forms.ModelForm):
    class Meta:
       model = UserMaster
       fields = ['username', 'password']
       widgets = {
            'username': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter User Name'}),
            'password': forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Enter Password'}),
            'password2': forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Confirm Password'}),
          }
       error_messages = {
            'username': {
                'required': ('Username cannot be empty'),
                'unique': ('Username already taken')},
            'password': {
                'required': ('Password cannot be empty')},
          'password2': {
             'required': ('Confirmation password cannot be empty')},
        }

    def __init__(self, *args, **kwargs):
       super(UserMasterForm, self).__init__(*args, **kwargs)
       for field in iter(self.fields):
          self.fields[field].widget.attrs.update({'class': 'form-control', })

views.py

def register_view(request):
    if request.method == 'POST':
        form = UserMasterForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('login')
        else:
            change_class_for_error(form)
            return render(request, 'mainapp/register.html', {'form': form})
    else:
        form = UserMasterForm()
        return render(request, 'mainapp/register.html', {'form': form})

def change_class_for_error(myform):
    for field in myform:
        if field.errors:
            myform.fields[field.name].widget.attrs['class'] = 'form-control is-invalid'

signup.html

<form action="" class="g-3 mx-2" method="POST" novalidate>
{% csrf_token %}
<div class="row">
    <div class="col-md-5">
        <label class="form-label">Username</label>
        {{ form.username }}
        {% for error in form.username.errors  %}
            <div class="invalid-feedback">{{ error }}
        {% endfor %}
    </div>
</div>
<div class="row">
    <div class="col-md-6">
        <label class="form-label">Password</label>
        {{ form.password }}
        {% for error in form.password.errors  %}
            <div class="invalid-feedback">{{ error }}
        {% endfor %}
    </div>
    <div class="col-md-6">
        <label class="form-label">Confirm Password</label>
        <input class="form-control {% if form.errors %} is-invalid {% endif %}"
               name="password2" type="text" >
        {% for error in form.password2.errors  %}
            <div class="invalid-feedback">{{ error }}
        {% endfor %}
    </div>
    <div class="flex gap-3 mt-3 mb-2">
        <button class="btn btn-primary button-label rounded-0 w-25" type="submit">
            <a class="text-decoration-none" href="">Save</a>
        </button>
        <button class="btn btn-warning button-label rounded-0 w-25" type="button">
            <a class="text-decoration-none" href="#">Cancel</a>
        </button>
    </div>
</div>
</form>

Instead of handling authentication yourself, you can set up a custom user model that behaves identically to the default user model by subclassing AbstractUser:


from django.contrib.auth.models import AbstractUser


class UserMaster(AbstractUser):
    pass

Then in your settings.py:


AUTH_USER_MODEL = 'users.UserMaster'

Where 'users` is the name of the app having your user model.

Also, register the model in the app’s admin.py:



from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import UserMaster

admin.site.register(UserMaster, UserAdmin)

You don't need to add password or confirm password fields in your form:


from django import forms
from django.contrib.auth.forms import (UserCreationForm) 

class UserMasterForm(forms.UserCreationForm):
    class Meta:
       model = UserMaster
       fields = ['username', 'email']

In your templates i.e. signup.html:


{% extends 'base.html' %}

{% load django_bootstrap5 %}

{% block title %}Sign Up{% endblock title %}
{% block content %}

<div class="signup-card">
<h2 class="text-primary">Sign Up</h2>
<form method="post">
  {% csrf_token %}
{% for field in form %}
  <div class="mb-3">
    <label class="form-label" style="width: 100%;">{{ field.label }}</label>
    {{ field }}
    {% if field.errors %}
      <div class="text-danger small">{{ field.errors }}</div>
    {% endif %}
  </div>
{% endfor %}
<button type="submit" class="btn btn-sm btn-primary">Sign Up</button>
</form>
</div>

{% endblock content %}

Note: This solution is ideal when starting a new project because changing AUTH_USER_MODEL after you’ve created database tables is possible, but can be complex, since it affects foreign keys and many-to-many relationships, for example.

This change can’t be done automatically and requires manually fixing your schema, moving your data from the old user table, and possibly manually reapplying some migrations.

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