Create a Custom User Model in Django
Tags: django, python
Published: 2020-01-03 12:23:33

In this article, we will be learning how to create a custom user model in Django. Why do you need a custom user while Django has it's own auth models? Well, the default user class doesn't offer adequate fields that may fully describe a user based on the type of application you're building. For instance, you may want to add the full name, gender, location, etc. Worry not since even with all that abstraction that comes with Django we can still be able to tweak a couple of things. Let's get to it. 

#### Let's Build
I am assuming you've already created a Django app and configured the database. I will be using Django 3.0.1 and Postgres 12.1. First, since the user model overrides the default user we need to define a custom `UserManager` class that extends `BaseUserManager`. We also have to ensure the class defines two methods; `create_user` and `create_superuser` methods. Create the user manager file under your startapp folder. Mine is in the path `src/authentication/user_manager.py`. Below is my project directory structure:
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/lyh6k042u5thmypw8mwu.png)

`user_manager.py`
```python
"""User manager model module"""
from django.contrib.auth.models import BaseUserManager


class UserManager(BaseUserManager):
    """ 
    custom user model
    """
    def create_user(
            self,
            email,
            password,
            is_active=False,
            is_staff=False,
            is_admin=False
        ):
        """Create user."""
        if not email:
            raise ValueError('Users must have an email address')
        user = self.model(email=self.normalize_email(email))
        user.is_active=is_active
        user.is_staff=is_staff
        user.is_admin=is_admin
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        """Create a superuser."""
        return self.create_user(
            email,
            password,
            is_active=True,
            is_staff=True,
            is_admin=True
        )

```
For the user to have superuser permissions like site administration, you have to add `is_superuser=True` or have the `has_perm` class method in your user model that references the admin field. In this case, we're going with the latter.

Create a `User ` model in the models file as below. Feel free to add any other fields as deemed necessary.

`models.py`
```python
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from authentication.user_manager import UserManager


class User(AbstractBaseUser, PermissionsMixin):
    """User model."""
    email = models.EmailField(unique=True, null=False)
    first_name = models.CharField(max_length=30, null=True)
    last_name = models.CharField(max_length=30, null=True)
    password = models.CharField(max_length=128, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)
    is_active = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)

    objects = UserManager()
    #unique identifier
    USERNAME_FIELD = 'email' 
    # any required fields besides email and password
    REQUIRED_FIELDS = []

    def __str__(self):
        return f'{self.first_name} {self.last_name}'

    @property
    def is_superuser(self):
        return self.is_admin

    def has_perm(self, perm, obj=None):
        return self.is_admin

```

`AbstractBaseUser`: Allows us to create a completely new User model.
`PermissionsMixin`: It will add fields that are specific for objects that have permissions, like `is_admin`.

Now add `{app_name}.User` to your `settings.py` file:
```python
AUTH_USER_MODEL = 'authentication.User'
```
Finally run the migrations. `$ python manage.py makemigrations && python manage.py migrate`

To be able to login to the admin dashboard we have to register our custom `User` model in Django admin sites. Open `app_name/admin.py` and add the code below.
```python
"""Register models to django admin."""
from django.contrib import admin
from django.contrib.auth.models import Group

from authentication.models import User

# list other models here
MODELS = [] 

class UserAdmin(admin.ModelAdmin):
    """Customize user/admin view on djano admin."""

    search_fields = ('email', )
    list_display = ('email', 'is_admin')
    list_filter = ('is_active', 'is_admin')
    ordering = ('email', )


    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Permissions', {'fields': ('is_admin','is_staff')}),
        ('Primary personal information', {
            'fields': ('first_name', 'last_name')}),
        ('Status', {'fields': ('is_active', )}),
    )


admin.site.register(User, UserAdmin)

for model in MODELS:
    admin.site.register(model)

```

To test the app start by creating a superuser:
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/py2xgsusvp8kmymbok6i.png)
Great! Now visit `http://127.0.0.1:8000/admin/` to login.

#### Conclusion
That's all for this article. You should now be able to tweak your user model to fit your application needs. Remember to add any new models under `MODELS` list of the admin file.  I hope you found it valuable and look out for more in the future!