0: Intro
The aim of this post will be explaining how to create a custom User Model
in Django. So we can use that email address
as the primary 'user identifier' instead of a username
for authentication.
Default Django app will give you a User Model
that has a mandatory username
field, and an 'optional' email
field.
However if you’re starting a new project, Django highly recommends you to set up a custom User Model
. For more info on this subject look at official doc: Custom User Model
In addition to that I usually need to set up email
as username
to
authenticate users in my apps.
1: Setup The Repo
-
I don't like django's default app template, therefore I created and using mine. You can clone this remote repo to run below code:
$ git clone https://github.com/serhatteker.com/django-template.git
-
Create a virtual environment named
.venv
:
$ virtualenv -p python3 .venv
-
Activate virtualenv:
$ source .venv/bin/activate
-
Install requirements:
$ pip install -r requirements.txt
-
Start an
app
named 'users':
$ mkdir src/app && python manage.py startapp src/users
-
Add the new app to the
INSTALLED_APPS
list into yoursettings.py
:
MY_APPS = [ 'src.core', 'src.users', ] INSTALLED_APPS = DJANGO_CORE_APPS + THIRD_PARTY_APPS + MY_APPS
2: Creating User Model
2.0 Creating Model Manager
First of all we need to add a custom Manager, by subclassing BaseUserManager
which uses an email
as the unique identifier instead of a username
.
Add below code to your users
' app model:
# src/users/model.py
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
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)
2.1 Creating User Model
2.1.0 AbstractUser vs AbstractBaseUser
As we mentioned before the default User Model
in Django uses a username
to
uniquely identify a user during authentication. If you'd rather use an email
address, you'll need to create a custom User model by either subclassing
AbstractUser
or AbstractBaseUser
.
-
AbstractUser
: If you are ok with the existing fields on theUser Model
and just want to remove the username field. -
AbstractBaseUser
: If you want to start from scratch by creating your own, completely newUser Model
.
2.1.1 Adding AbstractUser
We will use AbstractUser
since we only want to remove username
field and use django's very well designed User Model
.
Add below code into your model.py
:
# src/users/model.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
By adding above code we:
- Created a new class called
CustomUser
that subclassesAbstractUser
- Removed the
username
field - Made the
email
field required and unique - Set the
USERNAME_FIELD
which defines the unique identifier for theUser Model
toemail
- Specified that all objects for the class come from the
CustomUserManager
3: Update Settings
Add below line into your settings.py
for Referencing User Model:
AUTH_USER_MODEL = 'users.CustomUser'
4: Create Tables
Create new migrations and migrate them which will create a new database that uses our custom User Model
:
$ python manage.py makemigrations
$ python manage.py migrate
Note:
It is important that before applying migrations in your app
you must addCustomUser
into your model.
Again, I want to emphasize that before you apply your first
migration you must add your 'custom models'.
5: Admin
This is not a necessity; I mean that it doesn't throw an error when running your app. However I believe that it is more than "good-to-have". So we will add as well:
Add below code into your admin.py
:
# src/users/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
model = CustomUser
list_display = ('email', 'is_staff', 'is_active',)
list_filter = ('email', 'is_staff', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
That's it. From now on you can use our CustomUser
to authenticate users with email
and password
.
Now you can run the app:
$ python manage.py runserver
6: Test
When you create a superuser
, you should be prompted to enter an email
rather than a username:
$ python manage.py createsuperuser
Email address: user@test.api
Password:
Password (again):
Superuser created successfully.
All done!
Top comments (1)
EXACTLY WHAT I'M looking for thank a lot !