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.