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
appnamed 'users':
$ mkdir src/app && python manage.py startapp src/users -
Add the new app to the
INSTALLED_APPSlist 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 Modeland 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
CustomUserthat subclassesAbstractUser - Removed the
usernamefield - Made the
emailfield required and unique - Set the
USERNAME_FIELDwhich defines the unique identifier for theUser Modeltoemail - 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 addCustomUserinto 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 !