django_real_time_validation
Django and Ajax: Robust authentication and authorization system with real-time form validations for web applications
This website collects cookies to deliver better user experience
..Users can either login with any of Email/Password or Username/Password combination...
students registration
flow.Users fill in their details in the registration form;
If valid, a mail will be sent to the provided e-mail address during registration; then
On verification, by clicking the provided link which is only valid for one transaction, users can login.
Django and Ajax: Robust authentication and authorization system with real-time form validations for web applications
aacounts/forms.py
in a text editor and append the following:# accounts > forms.py
...
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
...
class StudentRegistrationForm(UserCreationForm):
username = forms.CharField(
widget=forms.TextInput(attrs={"placeholder": "Student number e.g. CPE/34/2367"})
)
def __init__(self, *args, **kwargs):
super(StudentRegistrationForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs["class"] = "validate"
class Meta:
model = get_user_model()
fields = (
"first_name",
"last_name",
"username",
"email",
"level",
"gender",
"password1",
"password2",
)
UserCreationForm
. This is one of the built-in forms in the framework. UserCreationForm
is simply a ModelForm with three fields inherited from user model — username, password1 and password2 — for creating users. This might not be necessary though since our form will be processed using AJAX. Still prefer using it....For students, their usernames must start with CPE and must be at least 9 characters long not counting any forward slash that it contains...
accounts/utils.py
and populate it with:# accounts > utils.py
import re
from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core import exceptions
USERNAME_MIN_LENGTH = 9
def is_valid_username(username):
if get_user_model().objects.filter(username=username).exists():
return False
if not username.lower().startswith("cpe"):
return False
if len(username.replace("/", "")) < USERNAME_MIN_LENGTH:
return False
if not username.isalnum():
return False
return True
def is_valid_password(password, user):
try:
validate_password(password, user=user)
except exceptions.ValidationError:
return False
return True
def is_valid_email(email):
if get_user_model().objects.filter(email=email).exists():
return False
if not re.match(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", email):
return False
if email is None:
return False
return True
def validate_username(username):
if get_user_model().objects.filter(username=username).exists():
return {
"success": False,
"reason": "User with that matriculation number already exists",
}
if not isinstance(username, six.string_types):
return {
"success": False,
"reason": "Matriculation number should be alphanumeric",
}
if len(username.replace("/", "")) < USERNAME_MIN_LENGTH:
return {
"success": False,
"reason": "Matriculation number too long",
}
if not username.isalnum():
return {
"success": False,
"reason": "Matriculation number should be alphanumeric",
}
if not username.lower().startswith("cpe"):
return {
"success": False,
"reason": "Matriculation number is not valid",
}
return {
"success": True,
}
def validate_email(email):
if get_user_model().objects.filter(email=email).exists():
return {"success": False, "reason": "Email Address already exists"}
if not re.match(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b", email):
return {"success": False, "reason": "Invalid Email Address"}
if email is None:
return {"success": False, "reason": "Email is required."}
return {"success": True}
is_valid_username
function, we are only ensuring that all tests are passed by the user:...
if get_user_model().objects.filter(username=username).exists():
return False
CPE
:
if not username.lower().startswith("cpe"):
return False
if len(username.replace("/", "")) < USERNAME_MIN_LENGTH:
return False
isalnum()
).is_valid_password()
uses django's validate_password
to ensure that user passwords pass django's password validations.is_valid_email()
ensures that provided email addresses are not None, unique and follow normal email pattern (such as person@domain).validate_*()
are helper functions for real-time validations.views.py
file.# accounts > views.py
...
from django.http import JsonResponse
...
from . import utils
...
def validate_email(request):
email = request.POST.get("email", None)
validated_email = utils.validate_email(email)
res = JsonResponse({"success": True, "msg": "Valid e-mail address"})
if not validated_email["success"]:
res = JsonResponse({"success": False, "msg": validated_email["reason"]})
return res
def validate_username(request):
username = request.POST.get("username", None).replace("/", "")
validated_username = utils.validate_username(username)
res = JsonResponse({"success": True, "msg": "Valid student number."})
if not validated_username["success"]:
res = JsonResponse({"success": False, "msg": validated_username["reason"]})
return res
POST
requests, they are passed in the functions we prepared before hand so as return some json data.urls.py
file:urlpatterns = [
...
path("validate-username/", views.validate_username, name="validate_username"),
path("validate-email/", views.validate_email, name="validate_email"),
]
from django.conf import settings
...
from django.contrib.sites.shortcuts import get_current_site
...
from . import tasks, utils
from .forms import LoginForm, StudentRegistrationForm
from .tokens import account_activation_token
...
def student_signup(request):
form = StudentRegistrationForm(request.POST or None)
if request.method == "POST":
post_data = request.POST.copy()
email = post_data.get("email")
username = post_data.get("username").replace("/", "")
password = post_data.get("password1")
if utils.is_valid_email(email):
user = get_user_model().objects.create(email=post_data.get("email"))
if utils.is_valid_password(password, user) and utils.is_valid_username(username):
user.set_password(password)
user.username = username
user.first_name = post_data.get("first_name")
user.last_name = post_data.get("last_name")
user.level = post_data.get("level")
user.gender = post_data.get("gender")
user.is_active = False
user.is_student = True
user.save()
subject = "Please Activate Your Student Account"
ctx = {
"fullname": user.get_full_name(),
"domain": str(get_current_site(request)),
"uid": urlsafe_base64_encode(force_bytes(user.pk)),
"token": account_activation_token.make_token(user),
}
if settings.DEBUG:
tasks.send_email_message.delay(
subject=subject,
template_name="accounts/activation_request.txt",
user_id=user.id,
ctx=ctx,
)
else:
tasks.send_email_message.delay(
subject=subject,
template_name="accounts/activation_request.html",
user_id=user.id,
ctx=ctx,
)
raw_password = password
user = authenticate(username=username, password=raw_password)
return JsonResponse(
{
"success": True,
"msg": "Your account has been created! You need to verify your email address to be able to log in.",
"next": reverse("accounts:activation_sent"),
}
)
else:
get_user_model().objects.get(email=post_data.get("email")).delete()
return JsonResponse(
{
"success": False,
"msg": "Check your credentials: your password, username, and email! Ensure you adhere to all the specified measures.",
}
)
context = {"page_title": "Student registration", "form": form}
return render(request, "accounts/student_signup.html", context)
if
statements to ensure all fields conform with the rules laid down before. We need to create tasks.py
and token.py
files. Go ahead and do that.