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.