image
March 8, 2023

Login user account with e-mail address

March 8, 2023

In the traditional approach, logging into a web application is done with a unique username and password. While this approach is widely used, it has some drawbacks that can affect user convenience. For example, users may have trouble remembering their username, leading to the need to retrieve login information.
 

One popular solution to these problems is to use an e-mail address as a unique identifier for logins. E-mail addresses are not only unique for each person, but also easier to remember. In addition, most users are already accustomed to using e-mail addresses as identifiers for various online services. Introducing e-mail address-based logins can contribute to users' convenience and satisfaction with applications.

 

In this article, we will show how to implement email address-based login in a Django application using AbstractUser and function-based views. We'll walk through the process of creating a user model, forms, views, and HTML templates using Bootstrap.

 

 

Creating a user model with AbstractUser

 

In order to implement email address login, we first need to create a custom user model that extends the built-in AbstractUser model. AbstractUser contains all the basic fields and methods necessary to manage user accounts. We will modify this model to use the email address as the primary identifier.

 

Here is how to build a custom user model:

# accounts/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(unique=True, blank=False, error_messages={'unique': "A user with that email already exists!"})

    account_type = models.CharField(choices=ACCOUNT_TYPE,  max_length=10)
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    objects = CustomUserManager()

    def __str__(self):
        return self.email

 

In the above code:

 

1. We import AbstractUser from django.contrib.auth.models and models from django.db.

 

2. we create a new CustomUser class that inherits from AbstractUser.

 

3. we override the email field in the CustomUser class by adding the unique=True attribute. This means that each email address must be unique for each user.

 

4. We set USERNAME_FIELD to 'email', which means that the email address will be used as an identifier when logging in.

 

5. We override the '__str__' method to return the user's email address

 

Now we need to update the application settings to use our custom user model:

# settings.py

AUTH_USER_MODEL = 'accounts.CustomUser'

 

In the code above, we replace 'accounts' with the name of the application that hosts the CustomUser model. AUTH_USER_MODEL tells Django that we want to use our custom user model instead of the default one.

 

In order for the CustomUser model to work properly, you will need the CustomUserManager, which is already included with the user model. Here is the code responsible for this functionality:

# accounts/managers.py

from django.contrib.auth.base_user import BaseUserManager

class CustomUserManager(BaseUserManager):
    """
    Custom user model manager where email is the unique identifiers
    for authentication instead of usernames.
    """
    def create_user(self, email, password, **extra_fields):
        """
        Create and save a User with the given email and password.
        """
        if not email:
            raise ValueError('The Email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        """
        Create and save a SuperUser with the given email and password.
        """
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self.create_user(email, password, **extra_fields)
    

 

Create forms for registration and login

 

Next, we need to create forms that will allow users to register and log in using their email address. To do this, we will create two forms: UserRegisterForm and EmailLoginForm. We create a new file named forms.py in the folder of our application and add the following code:

# accounts/forms.py

from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model

User = get_user_model()

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']

class EmailLoginForm(AuthenticationForm):
    username = None
    email = forms.EmailField()
    
    class Meta:
        model = User
        fields = ['email', 'password']

 

In the above code:

 

1. We import forms from django, UserCreationForm and AuthenticationForm from django.contrib.auth.forms and get_user_model from django.contrib.auth.

 

2. We retrieve a custom user model using the get_user_model function and assign it to the User variable.

 

3. we create a UserRegisterForm class that inherits from UserCreationForm. We add the email field as a required field to the form.

 

4. In the Meta class of UserRegisterForm, we set the model to our custom user model and define the list of fields to be included in the form.

 

5. we create the EmailLoginForm class, which inherits from AuthenticationForm. We set username to None, since we will use email address instead of username. We add the email field as a required field to the form.

 

6. In the EmailLoginForm Metaform class, we set the model to our custom user model and define the list of fields to be included in the form.

 

7. Now we have ready forms that will allow users to register and log in using their email address.

 

 

Implementation of views for registration and login

 

Now that we have the forms ready, we can create views that handle the registration and login process. To do this, we add the following code to the views.py file in our application folder:

# accounts/views.py

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import UserRegisterForm, EmailLoginForm

def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            messages.success(request, 'Konto zostało utworzone! Możesz się teraz zalogować.')
            return redirect('login')
    else:
        form = UserRegisterForm()
    return render(request, 'register.html', {'form': form})

def user_login(request):
    if request.method == 'POST':
        form = EmailLoginForm(request, request.POST)
        if form.is_valid():
            email = form.cleaned_data.get('email')
            password = form.cleaned_data.get('password')
            user = authenticate(request, email=email, password=password)
            if user is not None:
                login(request, user)
                return redirect('home')
    else:
        form = EmailLoginForm(request)
    return render(request, 'login.html', {'form': form})

def home(request):
    return render(request, 'home.html')

 

In the above code:

 

1. We import render, redirect functions from django.shortcuts module, login and authenticate functions from django.contrib.auth, UserRegisterForm and EmailLoginForm forms from forms.py file.

 

2. We create a register view function that handles POST and GET requests. If the request is POST, we create an instance of the UserRegisterForm form with the data submitted by the user. If the form is valid, we save the new user and display a success message, then redirect the user to the login page. If the request is GET, we display a blank registration form.

 

3. We create a user_login view function that handles POST and GET requests. If the request is POST, we create an instance of the EmailLoginForm form with the data submitted by the user. If the form is valid, we attempt to authenticate the user using the authenticate function and pass in the email address and password. If the authentication is successful, we log the user in, display a welcome message and redirect the user to the home page. If the request is GET, we display a blank login form.

4. We create a home view function to which users will be redirected after they have successfully logged into the application. In a real-world solution, it can definitely be expanded more, but in this example it will only be used to confirm whether the login was successful.

 

Having the views ready, we can move on to creating HTML templates.

 

 

Creating HTML templates using Bootstrap

 

In this subsection, we'll look at creating HTML templates for our registration and login views using Bootstrap to quickly and easily create attractive and responsive forms. First, we'll create a templates folder in our application's folder, with two files in it: register.html, login.html and home.html.

 

Let's start with the register.html template:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rejestracja</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h2>Registration</h2>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="btn btn-primary">register</button>
        </form>
    </div>
</body>
</html>

 

In the above template:

 

1.We load the static tag at the beginning of the file to be able to use static files (however, this is not used in this particular template).

 

2.We add a basic HTML5 structure with meta tags, a title tag and a link to the Bootstrap stylesheet.

 

3. we create a container in which we place the registration form. The form uses the POST method, and the csrf_token tag provides security against CSRF attacks.

 

4. We display the form using {{ form.as_p }}, which will generate a form with the fields contained inside the <p> tags.

 

5. We add a "Register" button with Bootstrap class "btn btn-primary".

 

Now let's go to the login.html template:

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Log in</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h2>Log in</h2>
        <form method="post">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="btn btn-primary">Log in</button>
        </form>
    </div>
</body>
</html>

 

The login.html template is very similar to register.html. The differences are changing the title to "Login" and the button to "Login".

 

Finally, the home.html template, after successful login, users will be redirected to it.

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Rejestracja</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h1>Successful login!</h1>
        <h2>you are now logged in based on your email address</h2>
    </div>
</body>
</html>

 

 

With the templates ready, we can now add the appropriate URLs to integrate our views with the rest of the application. To do this, we edit the urls.py file in our application's folder, adding the following paths:

from django.urls import path
from . import views

urlpatterns = [
    path('register/', views.register, name='register'),
    path('login/', views.user_login, name='login'),
    path('home/', views.home, name='home'),
]

 

In the above code:

 

1. We import path from the django.urls module and views from our application.

 

2. We add paths for the register, user_login and home views, assigning them appropriate names.

 

In this way, we have integrated our registration and login views into the Django application. Now users can register and log in using their email address.

 

 

Example of user registration and login

 

In this part of the post, we will show how the user registration and login process looks like in our Django application. Recall that we have implemented registration and login functions that use an email address instead of a username.

 

To test our implementation, follow the steps below:

 

Prepare and perform a database migration.

python manage.py makemigrations
python manage.py migrate

 

1. start the Django development server by typing in the console:

python manage.py runserver

 

2. Open your browser and go to the registration URL, for example: http://127.0.0.1:8000/register/. You will see the registration form we created earlier.

 

3. Fill out the form with your email address, password and repeated password. Make sure the password you provide meets security requirements, such as length and unique characters.

 

4. Click the "Register" button. If the form has been filled out correctly, you will be redirected to a login page with information about the successful creation of your account.

 

5. Navigate to the login URL, for example: http://127.0.0.1:8000/login/. You will see the login form that we also created earlier.

 

6. Enter the email address and password you used during registration, and then click the "Login" button.

 

7. If your login information is correct, you will be redirected to the application's home page (or another page we defined after logging in).

Discussion

Your comment

Tags