Django comes with a default user model that's used for the standard authentication system. If you had worked on Django you probably have seen this authentication page.
We're going to override this model with our own custom model that allows us to use an Email
instead of the standard Username
that comes with the Django default model.
We're gonna modify models.py
file to include our user profile model.
The first thing we need to do is import some additional classes at the top.
AbstractBaseUser
According to Django documentation AbstractBaseUser
has the authentication functionality only , it has no actual fields, you will supply the fields to use when you subclass.
PermissionsMixin
Django provides PermissionsMixin
. This is an abstract model you can include in the class hierarchy for your user model, giving you all the methods and database fields necessary to support Django’s permission model.
BaseUserManager
If your user model defines username
, email
, is_staff
, is_active
, is_superuser
, last_login
, and date_joined
fields the same as Django’s default user, you can install Django’s UserManager
; however, if your user model defines different fields, you’ll need to define a custom manager that extends BaseUserManager
.
Add this lines at top of the file.
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
Creating UserProfile Class.
Underneath the imports let's create a new class called UserProfile
and inherit from the AbstractBaseUser
and PermissionsMixin
class UserProfile(AbstractBaseUser, PermissionsMixin):
""" Database model for users in the system """
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
objects = UserProfileManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def __str__(self):
""" Return string representation of our user """
return self.email
By adding above code we:
- Made the
email
andname
field required and madeemail
unique - Set the
USERNAME_FIELD
which defines the unique identifier for theusername
toemail
. - Specified that all objects for the class come from the
UserProfileManager
Creating UserProfileManager Class.
Now that we have our custom user model we can go ahead and create a manager. Now because we've customized our model we need to tell Django how to interact with this user model in order to create users because by default when it creates a user it expects a user name field and password field but we replace the user name field with an email field.So we just need to create a custom manager that can handle creating users with an email field instead of a user name field.
Let's create a new class called UserProfileManager
and inherit from the BaseUserManager
.
class UserProfileManager(BaseUserManager):
""" Manager for user profiles """
UserProfileManager
the way it manages work is you specify
some functions within the manager that can be used to manipulate objects within the module that the manager is for.
Below are two functions which we need to add in UserProfileManager
class.
def create_user(self, email, name, password=None):
""" Create a new user profile """
if not email:
raise ValueError('User must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, name=name)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, password):
""" Create a new superuser profile """
user = self.create_user(email,name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
Above code sets logic for when one creates users and superusers using Django CLI.
Update Settings to use Custom Model.
We need add below line in settings.py
to use this model over default one.
AUTH_USER_MODEL = 'App_name.UserProfile'
Make changes in Database.
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
Create superuser
$ python manage.py createsuperuser
Email address: chokshiroshan@gmail.com
Password:
Password (again):
Superuser created successfully.
Test
As you can see instead of asking for Username
it is prompting for Email
.
Top comments (2)
So, I implemented this one (well, this one has issues - so, I followed what's on: medium.com/@royprins/django-custom... ) but now I see a problem. Only the superuser/admin can login with email address. 'authenticate' and 'login' fails for regular user. I have created a custom 'authenticate()' but then 'login()' still fails. Any idea or suggestion?
This will crash after login and bring all kinds of issues as the user is missing required fields (e.g. is_stuff)