Sławomir Kwiatkowski

by: Sławomir Kwiatkowski

2024/09/26

Django - new user model & manager

Content description:
In this post I'll describe how to create your own user model in Django.
Then I'll test the model and manager I created.

First, I create a new application called users.

     
python manage.py startapp users

In the models.py file, I create a custom user that inherits from the AbstractUser class. I add a checkbox in the profile so that a user can be a client or a contractor. A client issues delivery orders to warehouses, and a contractor accepts them.

Each user, in addition to a unique name and password, must have an email address. The default user account is inactive - you can't log in to it. Only account activation using an email address allows you to log in to the user account. The user account is created using ContractUserManager.

     
from django.db import models
from django.contrib.auth.models import AbstractUser
from .managers import ContractUserManager


class ContractUser(AbstractUser):

    class ProfileChoices(models.TextChoices):
        CLIENT = "client"
        CONTRACTOR = "contractor"

    profile = models.TextField(
        choices=ProfileChoices.choices, default=ProfileChoices.CLIENT
    )
    email = models.EmailField(max_length=255, unique=True)
    is_active = models.BooleanField(default=False)

    objects = ContractUserManager()

    def __str__(self):
        return self.username

The new user model should be registered in the project's settings.py file, i.e.

     
AUTH_USER_MODEL = "users.ContractUser"

ContractUserManager inherits from the UserManager class. With the manager, you can create regular and privileged users. Privileged user accounts do not require activation.

     
from django.contrib.auth.models import UserManager
from django.utils.translation import gettext_lazy as _


class ContractUserManager(UserManager):

    def create_user(self, username, email, password, **extra_fields):
        if not email:
            raise ValueError(_("Email field is required"))
        email = self.normalize_email(email)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, username, email, password, **extra_fields):
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_active", True)
        user = self.create_user(username, email, password, **extra_fields)
        return user


Testing a regular user as well as a privileged user:

     
from django.test import TestCase
from .models import ContractUser


class ContractUserTestCase(TestCase):

    def setUp(self):
        self.user = ContractUser.objects.create_user(
            username="user", password="123", email="user@company.com"
        )
        self.superuser = ContractUser.objects.create_superuser(
            username="admin",
            password="123",
            email="admin@company.com",
        )

    def test_create(self):
        self.assertEqual(self.user.username, "user")
        self.assertEqual(self.user.email, "user@company.com")
        self.assertEqual(self.user.profile, "client")
        self.assertEqual(str(self.user), "user")
        self.assertFalse(self.user.is_active)

        with self.assertRaisesMessage(ValueError, "Email field is required"):
            ContractUser.objects.create_user(username="user1", email="", password="123")

    def test_create_superuser(self):
        self.assertTrue(self.superuser.is_superuser)
        self.assertTrue(self.superuser.is_staff)
        self.assertTrue(self.superuser.is_active)
        self.assertEqual(self.superuser.username, "admin")

In the next post I'll describe in more detail the Django Rest Framework.