When creating a Django program you might want to have different users with varied permissions and features accessible to them. I've seen that this is a typical difficulty that many developers face in the early phases of development, therefore I've decided to offer my expertise on the subject in the most straightforward and accessible manner possible.
Note: This tutorial isn't for absolute beginners, you must have a basic understanding of Python and Django or you will find it difficult to follow along.
There are different ways of managing multiple types of users, one thing that often comes to mind when developers think about this feature is to have different user models to manage different types of users but this isn't what you want to do, you want to use only one Django model to handle authentication regardless of your strategy or business model. In this article we are going to separate users by making use of flags.
Let's take into consideration the default Django model, you are already managing two types of users which are the normal users and the superuser. These two types of users are not managed by two separate models instead they manage these users with flags. For a clearer picture consider the is_staff
flag and the is_superuser
flag, the is_staff
flag grants a user permissions to login the admin panel and the is_superuser
flag grants a user all permissions so they can create and delete any database data that is registered to the admin panel.
Now you should have a clearer understanding of how we can manage multiple user types in one user model using flags. We are now going to create a custom user model to implement this feature and the respective view where users can sign up to be an admin or a normal user.
To follow this tutorial you should have a virtual environment running, must have Django and Django Rest Framework installed with the commands pip install django
and pip install djangorestframework
, started a new project with django-admin startproject projectname
and also created an app inside of your project.
Step 1: Create the user model
In your user's app models.py file, we inherit from the AbstractBaseUser
and the BaseUserManager
. Basically, they are classes we could use to extend the generic Django user model and create a custom user model.
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
class Account(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
name = models.CharField(max_length=30)
date_joined = models.DateTimeField(verbose_name='date_joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = MyAccountManager()
def __str__(self):
return self.email
In the code snippet above you can see that by default the is_admin
, is_staff
and is_superuser
fields are set to false, this implies that by default all registered users should be normal users. To create admin users or a superuser we must then apply the use of flags to separate these users when created, this would be done in your user model manager class which inherits from the BaseUserManager
class.
Step 2: Create the User model manager
class MyAccountManager(BaseUserManager):
def create_user(self, email, name, password=None):
if not email:
return ValueError("Users must have an email address")
if not name:
return ValueError("Users must have a name")
user = self.model(
email=self.normalize_email(email).lower(),
name=name,
password = password,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_admin(self, email, name, password=None):
user = self.create_user(
email=self.normalize_email(email),
password = password,
name = name,
)
user.is_admin = True
user.save(using=self._db)
return user
def create_superuser(self, email, name, password=None):
user = self.create_user(
email=self.normalize_email(email),
password = password,
name = name,
)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
In the above code snippet, the def create_admin
function will be executed only when the is_admin
flag is set to the boolean value True
and then an admin user would be created. The class MyAccountManager
could be named anything really but I think it makes more sense since the name of our user model is Account
. Now you can create multiple admin users and a superuser.
Step 3: Setting the model you just created
In the settings.py file of our project's base directory set AUTH_USER_MODEL = 'users.Account'
, here users is the name of the user app and Account is the model we just created. We are overriding the default user model Django provides and making reference to the one we just built.
Step 4: We migrate
we go to our terminal and the location of the current working file, activating the required virtual environment and run python manage.py makemigrations
and python manage.py migrate
. The python manage.py makemigrations
prepares the created model to be converted to sql format and the python manage.py migrate
commit those changes.
Step 5: Creating the user registration APIViews
Here we are going to create the APIViews which we would use to register users. In our case we want to register either a normal user or an admin user, by now it should all be coming together, we want the boolean value True
to be passed when creating admin users and False
when creating normal users. Let us see how we can accomplish this In our users app views.py file using the Django rest framework.
from django.contrib.auth import get_user_model
User = get_user_model()
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework import status
class RegisterView(APIView):
permission_classes = (AllowAny, )
def post(self, request):
try:
data = request.data
name = data['name']
email = data['email']
email = email.lower()
password = data['password']
re_password = data['re_password']
is_admin = data['is_admin']
if is_admin == 'True':
is_admin = True
else:
is_admin = False
if password == re_password:
if len(password) >= 8:
if not User.objects.filter(email=email).exists():
if not is_realtor:
User.objects.create_user(name = name, email = email, password = password)
return Response(
{'success': 'User created Sucessfully.'},
status=status.HTTP_201_CREATED
)
else:
User.objects.create_admin(name = name, email = email, password = password)
return Response(
{'success': 'Admin user created sucessfully.'},
status=status.HTTP_201_CREATED
)
else:
return Response(
{'error': 'User with this email already exists.'},
status = status.HTTP_400_BAD_REQUEST
)
else:
return Response(
{'error': 'Password must be at least 8 characters.'},
status = status.HTTP_400_BAD_REQUEST
)
else:
return Response(
{'error': 'Passwords do not match.'},
status = status.HTTP_400_BAD_REQUEST
)
except:
return Response(
{'error': 'Something went wrong while registering.'},
status = status.HTTP_500_INTERNAL_SERVER_ERROR
)
Imports
Above we are using the
get_user_model
function to get our user model, we then set it to the variable User and execute it. We importAPIView
to make this function an api view,AllowAny
to give permissions to any user to access the registration endpoint ,Response
andstatus
to return a response and the status respectively.Body
First we retrieve the request data and store it in the value data
data=request.data
, data will be a dictionary and the values of data will be strings. We can then retrieve the string values of data respectively. If the string value of the flagis_admin
passed is"True"
then we setis_admin
to the boolean valueTrue
and vice versa. Just with one flag we can now separate normal users from admin users.
Step 6: We create our url endpoints
from django.urls import path
from . views import RegisterView
urlpatterns = [
path('register', RegisterView.as_view(), name='api-register'),
]
Finally, we can now use this url endpoint to make requests to either create a normal user or an admin user. We can also set different roles for the different users and permissions to enforce the roles.
Conclusion:
You should never user more than one user model to handle authentication regardless of your strategy or business model. The use of flags which was covered in this tutorial is an effective way to separate user types although there are other ways this can be accomplished.
Thank you for reading and I hope you find this article useful and informative. ๐