Using email instead of a username for login is more user-friendly and often preferred in modern applications. Django supports this, but it requires a custom user model. Here's how to set it up cleanly and correctly.


✅ Step 1: Create a Custom User Model

In your core/models.py (or any appropriate app), define a user model using AbstractBaseUser and PermissionsMixin:

from django.contrib.auth.models import (
    AbstractBaseUser,
    BaseUserManager,
    PermissionsMixin,
)
from django.db import models

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError("Email is required")
        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=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        return self.create_user(email, password, **extra_fields)

class AppUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    full_name = models.CharField(max_length=150)
    phone_number = models.CharField(max_length=20, blank=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["full_name"]

    def __str__(self):
        return self.email

✅ Step 2: Point Django to Your New User Model

In settings.py:

AUTH_USER_MODEL = "core.AppUser"

Make sure this is set before running any migrations.


✅ Step 3: Create and Apply Migrations

python manage.py makemigrations core
python manage.py migrate

This sets up your database using the email field as the login ID.


✅ Step 4: Use get_user_model() Everywhere

Avoid importing User directly. Use this in views, tests, and signals:

from django.contrib.auth import get_user_model

User = get_user_model()

Example usage in tests:

User.objects.create_user(email="[email protected]", password="testpass")

✅ Step 5: Create Superuser with Email

When creating a superuser via script or CLI, use:

python manage.py createsuperuser --email [email protected] --full_name "Admin"

If you use --noinput, pass in the --email and --full_name values explicitly in your script.


✅ Done

You now have a Django project where email is the unique identifier for login. This setup is clean, minimal, and aligns with real-world authentication flows.