36. Account creation

Next, we will implement the user account creation system.

Within the create_account.html file, we will configure the account creation form to submit its data to the create_account URL endpoint.

create_account.html
<form method="POST" action="{% url 'create_account' %}">

Django already validates the email using the email tag in the HTML form, but for additional security and reliability, we will also validate the email within the create_account view function.

Inside the views.py file, we will import the validate_email function and the ValidationError exception, as the error message returned by the function is not a default Python exception.

views.py
from django.core.validators import validate_email
from django.core.exceptions import ValidationError

To verify the passwords obtained via the forms, we will create a utility function called secure_password inside the utility.py file. This function will analyze the password passed as a parameter and return True if it meets all the previously mentioned criteria.

views.py
from .utility import filter_product, min_max_price, order_products, secure_password

To enhance user security, we will enforce the following password criteria:

  • Must be between 8 to 20 characters.

  • Must contain at least:

    • One uppercase letter.

    • One lowercase letter.

    • One special character.

utility.py
def secure_password(password: str) :
    if len(password) < 8 or len(password) > 20:
        return False
    special_characters = set('" "!@#$%^&*()-+?_=,<>/""''|.;:')
    has_lower = has_upper = has_number = has_special = False

    for character in password:
        if character.islower():
            has_lower = True
        elif character.isupper():
            has_upper = True
        elif character.isdigit():
            has_number = True
        elif character in special_characters:
            has_special = True
        
        if has_lower and has_upper and has_number and has_special:
            return True

    return False

Next, we will edit the create_account view function to implement the account creation functionality:

views.py
def create_account(request):
    error = None
    if request.user.is_authenticated:
        return render(request, 'user/create_account.html')
    
    if request.method == "POST":
        data = request.POST.dict()
        email = data.get("email", "").strip()  # Ensure email is stripped of whitespace
        password = data.get("password")
        confirm_password = data.get("confirm_password")
        
        if email and password and confirm_password:  # Check if all fields are filled
            try:
                validate_email(email)  # Validate email format
            except ValidationError:
                error = "invalid_email"
            else:
                if secure_password(password) :
                    if password == confirm_password:
                        user, created = User.objects.get_or_create(username=email, email=email)
                        if not created:
                            error = "user_exists"
                        else:
                            user.set_password(password)
                            user.save()  # Save the user
                            
                            # Authenticate and log in the user
                            user = authenticate(request, username=email, password=password)
                            if user is not None:
                                login(request, user)
                                
                                # Handle client creation or update
                                id_session = request.COOKIES.get("id_session")
                                if id_session:
                                    client, created = Client.objects.get_or_create(id_session=id_session)
                                else:
                                    client, created = Client.objects.get_or_create(email=email)
                                client.user = user
                                client.email = email
                                client.save()
                                
                                return redirect('store')
                    else:
                        error = "different_password"
                else :
                    error = "weak_password"
        else:
            error = "fill"
    
    context = {"error": error}
    return render(request, 'user/create_account.html', context)

The code above can be described below:

  • Function Name: create_account

  • Parameters: request (HTTP request object)

  • Local Variable: error initialized to None

Authentication Check

  • Check: If user is authenticated

    • Action: Render the 'create_account.html' template

HTTP POST Method Handling

  • Check: If request method is "POST"

    • Action: Convert request.POST data to dictionary (data)

Form Data Validation

  • Check: Presence of 'email', 'password', and 'confirm_password' in data

    • Action: Extract 'email', 'password', and 'confirm_password' from data

Email Validation

  • Try: Validate email format using validate_email

    • Exception: Set error to "invalid_email" if ValidationError occurs

Password Confirmation

  • Check: If 'password' matches 'confirm_password'

    • Action: Attempt to create or get a User with given 'email'

User Existence Check

  • Check: If user already exists

    • Action: Set error to "user_exists" if user already exists

New User Creation

  • Action: Set user's password and save the user object

User Authentication and Login

  • Action: Authenticate user with provided 'email' and 'password'

    • Action: Log in the authenticated user

Session Handling for Anonymous Users

  • Check: If "id_session" exists in cookies

    • Action: Get or create Client with 'id_session'

    • Else: Get or create Client with 'email'

Client Association

  • Action: Associate Client with the authenticated user

  • Action: Save Client object

Redirect and Error Handling

  • Redirect: Redirect to 'store' on successful account creation

  • Else: Set error to "different_password" if passwords do not match

  • Else: Set error to "fill" if required fields are missing

Context and Template Rendering

  • Context: Pass error to context dictionary

  • Render: Render 'create_account.html' with context

Note: The Client model is used to store all the user's information. This model is linked to the User model in a one-to-one relationship.

The account creation system is now fully operational, as demonstrated in the images below:

Creating a account (client)
The Client instance is successfully created, indicating that the account creation system is functioning as expected.

Note: The cart content of anonymous users is preserved and associated with their account upon account creation throught their Id session.

It stores the session ID of the anonymous client, allowing the system to retain and associate their cart content with their newly created account.

Last updated