How to Create/Extend Django Custom User Model
Tags: django, programming, webdev
Published: 2020-05-31 10:03:37

Originally Published at [Learnitfree.org](https://learnitfree.org/) as a blog post [Django Custom User Model](https://learnitfree.org/django-custom-user-model/)

![Django Custom User Model](https://learnitfree.org/wp-content/uploads/2020/05/How-to-Create-Extend-Django-Custom-User-Model.jpg)

The Django build-in `User` model out of the box is solid. But it sometimes might not suit your need since it has some predefined field and you might want to add some more field to it like Date of Birth or maybe making email-only authentication since Django has username-password authentication out of the box. That’s when Django’s custom user model comes handy.

Django uses Python language. If you want to learn Python go to Learn Python from the [Best Free Python Courses and Tutorials](https://learnitfree.org/subject/learn-python/).

## Do I need a Custom User Model?

Most of the time you don’t. Django’s built-in `User` models provide more than enough features to serve you out of the box. But if you want the user to authenticate with an email address instead of username then the custom model could be the right choice.

But that being said [Django Official documentation](https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project) suggests you have a custom model even if you don’t want too so in future if you want to add more information about the user you can do so which is more likely if your app grows.

### Application-specific data

The `User` model is meant to show information related to your user’s authentication or authentication point of view. You might even be tempted to store other application-specific information related to the user.

Since most users will have a profile picture, bio. Data like this could be stored in another model which is referenced with an `OneToOneField` with the `User` Model.

### Storing application data on the User model

There are some advantages and disadvantages to storing application data in the user model.

-   For smaller applications, it will be simpler. There won’t be many things to look for. Everything in one place. But if the application grows the same model can become clutter in no time.
-   Since everything will be in one place there won’t be a need for advanced database queries. But that would also make your table in the database bloated.

### Storing application data in a profile model

The alternative way to store your user application data is to have another model `Profile` which is referenced with `OneToOneField` to the `User` Model.

-   Since the application data is kept on another model the `User` model is only used for authentication purposes and the `Profile` model is used for user’s application data. Keeping it clutter-free.
-   But since the application data is different from authentication data than to get the user application data we need to load another object from the database in order to retrieve the data. Depending on your application it could be worth the effort.
-   The decoupling of application data with authentication data makes it easier to make changes in the future.

## Default Fields of User Model

The `User` Model Django provides out of the box has some fields in general:

1.  `username`: The username that the user will use to authenticate. This will be unique in the table.
2.  `email`: The email that the user can choose to share. But out-of-the-box it is not unique.
3.  `password1`: The password user chooses to authenticate. It is not a plain password. It will be hashed for security reasons.
4.  `password2`: This is used for confirm password. At the Admin side, only one field named password is seen.
5.  `first_name`: First name of the person.
6.  `last_name`: Last name of the person.
7.  `last_login`: The last Date and Time the user logged in.
8.  `date_joined`: The Date and Time the user joined/authenticated with your website.
9.  `groups`: The groups the user is in.
10.  `user_permissions`: Admin permissions if any.
11.  `is_staff`: Designates whether the user can log into the admin site.
12.  `is_active`: Designates whether this user should be treated as active. Unselect this instead of deleting accounts.
13.  `is_superuser`: Designates that this user has all permissions without explicitly assigning them.

## Ways to Extend the `User` model

There are 4 ways to extend an existing `User` model in Django. Check them below and choose the one that fits your needs.

1.  Proxy Model
2.  `Profile` Model with `OneToOneField` with `User` Model
3.  `AbstractBaseUser` to Create a Custom `User` Model
4.  `AbstractUser` to Create a Custom `User` Model

### 1\. Proxy Model

Proxy models are a feature that developers might come across and move along without giving much importance. They can come in handy in many situations.

A proxy model is just another class that provides a different interface for the same underlying database model.

A proxy model is actually a subclass of a database-table defining model. Typically creating a subclass of a model results in a new database table with a reference back to the original model’s table ie. multi-table inheritance.

A proxy model doesn’t get its own database table. Instead, it operates on the original table.

It is used to change the behavior of an existing model (e.g. order, new methods, etc.) without changing the existing database schema.

When to use Proxy Model?

When you don’t need to add extra data about but just want extra methods or change the model’s query Manager.

It is a less intuitive way to extend the existing User model and is limited in many ways. You won’t have any drawbacks with this strategy.

`models.py`

``` python
from django.contrib.auth.models import User
from .managers import PersonManager

class Person(User):
    objects = PersonManager()

    class Meta:
        proxy = True
        ordering = ('email', )

    def do_something(self):
        ...
``` 

Let see what we did here.

-   First, we defined a Proxy Model named Person. To tell Django that it is a proxy model we make `proxy = True` in `class Meta`.
-   We assign a custom Manager named `PersonManager` to the Proxy model by `objects = PersonManager( )`.
-   Change the default ordering to `email`.
-   Defined a function `do_something`.

Also now `User.objects.all( )` and `Person.objects.all( )` will be using the same database table to query. The only difference has been the behavior of the Proxy Model.

### 2\. Profile Model with OneToOne link with User Model

The idea behind this is to create another table in the database and point the `User` model to that table in the database with `OneToOneField`.

What is OneToOne Link?

It’s the Foreign Key relation but with `unique=True`. So every row in a table would have only one relating row in another table and vice versa.

But, when should I use this?

You should do this when you want to store profile related information like a profile picture, bio, etc. Basically everything related to the user that is not authentication specific.

Most of the time this is what you want.

Since we will be creating another model that stores user’s profile data that will be related to the `User` model. This will need an additional query or join to access the related data. To access the related data Django needs to fire additional queries.

So let’s see what to do here,

`models.py`

``` python
from django.db import models
from django.contrib.auth.models import User

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.CharField(null=True, max_length=200)
		birth_date = models.DateField(null=True, blank=True)    
		profile_pic = models.ImageField(default='default.jpg', upload_to='profiles_pics')
		hobby = models.CharField(null=True, max_length=200)
``` 

Now since the models are created, but they need to be created whenever a user is created. We need to use signals to do the same.

`models.py`

``` python
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.CharField(null=True, max_length=200)
		birth_date = models.DateField(null=True, blank=True)    
		profile_pic = models.ImageField(default='default.jpg', upload_to='profiles_pics')
		hobby = models.CharField(null=True, max_length=200)

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
	if created:
		Profile.objects.create(user=instance)

@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
	instance.profile.save()
``` 

Here, we are telling Django that whenever a save event occurs (signal called `post_save`) create or save the profile depending on the situation.

So, here whenever an entry/row of a user is created in the table, a new entry/row is also created in the profile table in the database.

But that’s all fine, how do I access this profile data?

You can access this data in Django Templates like:

`template.html`

``` HTML
<h2>{{ user.username }}</h2>
<p>{{ user.email }}</p>
<p>{{ user.profile.bio }}</p>
<p>{{ user.profile.birth_date }}</p>
``` 

For using it in views:

`views.py`

``` python
def update_profile(request, user_id):
    user = User.objects.get(pk=user_id)
    user.profile.hobby = 'Coding, Chess, Guitar'
    user.save()
``` 

Since we have signals setup we don’t have to save the `Profile` models. If we save the `User` model the `Profile` models will also be saved.

In Django, we can have multiple forms in the same templates at once. So, if we want to have a profile page where users email, username and other profile data like bio, etc is shown and can be updated by the user.

First, we will create the forms: `form.py`

`forms.py`

``` python
from django import forms
from django.contrib.auth.models import User
from .models import Profile

class UserUpdateForm(forms.ModelForm):
	email = forms.EmailField()

	class Meta:
		model = User
		fields = ['username', 'email']

class ProfileUpdateForm(forms.ModelForm):
	class Meta:
		model = Profile
		fields = ['profile_pic', 'bio']
``` 

To access the forms in `views.py`

``` python
@login_required
def profile(request):
	if request.method == 'POST':
		u_form = UserUpdateForm(request.POST, instance=request.user)
		p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)

		if u_form.is_valid() and p_form.is_valid():
			u_form.save()
			p_form.save()
			messages.success(request, f'Your Profile has been Updated Successfully')
			return redirect('profile')
	else:	
		u_form = UserUpdateForm(instance=request.user)
		p_form = ProfileUpdateForm(instance=request.user.profile)
	context = {
		'u_form': u_form,
		'p_form': p_form
	}
	return render(request, 'users/profile.html', context)
``` 

The template: `profile.html`

``` HTML
<form method="POST" enctype="multipart/form-data">
	{% csrf_token %}
	<fieldset class="form-group">
		<legend class="border-bottom mb-4">Profile Info</legend>
		{{ u_form.as_p }}
		{{ p_form.as_p }}
	</fieldset>
	<button type="submit">Update</button>
</form>
``` 

### 3. `AbstractBaseUser` to Create a Custom User Model

This method is like starting from a clean slate. Use this method if you want to start from scratch.

This method will have no predefined field, it only contains the authentication functionality, but no actual fields. You have to supply them when you subclass.

It can be helpful in many cases like when you want to use email for authentication instead of username. But there are better ways to do the same by using `AbstractUser` instead of `AbstractBaseUser` .

You this at your own will. JK. You will be fine.

To demonstrate this we will be using the same example as in the documentation.

Here is an example of an admin-compliant custom user app. This user model uses an email address as the username, and has a required date of birth; it provides no permission checking beyond an admin flag on the user account.

This model would be compatible with all the built-in auth forms and views, except for the user creation forms. This example illustrates how most of the components work together, but is not intended to be copied directly into projects for production use.

This code would all live in a `models.py` file for a custom authentication app:

`models.py`

``` python
from django.db import models
from django.contrib.auth.models import (
    BaseUserManager, AbstractBaseUser
)

class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, date_of_birth, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class MyUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['date_of_birth']

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin
``` 

Then, to register this custom user model with Django’s admin, the following code would be required in the app’s `admin.py` file:

`admin.py`

``` python
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField

from users.models import MyUser

class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = MyUser
        fields = ('email', 'date_of_birth')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user

class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]

class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'date_of_birth', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('date_of_birth',)}),
        ('Permissions', {'fields': ('is_admin',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'date_of_birth', 'password1', 'password2'),
        }),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()

# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
``` 

Finally, specify the custom model as the default user model for your project using the `AUTH_USER_MODEL` setting in your `settings.py`:

`settings.py`

``` python
AUTH_USER_MODEL = 'users.MyUser'
```

### 4. `AbstractUser` to Create a Custom User Model

This is pretty simple to start with and is flexible too. `AbstractUser` is your `User` Model the Django framework provides out of the box. Since you will be subclassing it. So now you can change stuff inside the class like using `email` field instead of `username` field for authentications.

`AbstractUser` is a full `User` model, complete with fields, like an abstract class, so that you can inherit from it and add your own profile fields and methods.

`models.py`

``` python
from django.db import models
from django.contrib.auth.models import AbstractUser

class MyUser(AbstractUser):
    bio = models.TextField(max_length=500, blank=True)
    hobby = models.CharField(max_length=200, blank=True)
``` 

Update your `setting.py` to use the new `User` Model

`settings.py`

``` python
AUTH_USER_MODEL = 'users.MyUser'
```

Where `users` is the app’s name

*Django recommends having your own custom model even if you happy with the out of the box User model.*

What to do if I just need the default User Model and don’t want to add any other fields?

Do it like this:

`models.py`

``` python
from django.contrib.auth.models import AbstractUser

class MyUser(AbstractUser):
    pass

    def __str__(self):
        return self.username
``` 

And obviously, tell Django to use your Custom User Model in settings.py

`settings.py`

``` python
AUTH_USER_MODEL = 'users.MyUser'
```

## Referencing the `User` model

Now since you have changed your default `User` Model. You might need to change the way you access it.

Now in Option 2 where we used `OneToOneField` in `Profile` Model to relate to `User` model like this:

`models.py`

``` python
from django.db import models
from django.contrib.auth.models import User

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
		# Other Fields
``` 

After using our Custom Model, the right/better way is to use `get_user_model( )`, like this:

`models.py`

``` python
from django.db import models
from django.contrib.auth import get_user_model

class Profile(models.Model):
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
		# Other Fields
``` 

or

`model.py`

``` python
from django.db import models
from django.conf import settings

class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
		# Other Fields
``` 

Up to you what you choose. Both will work fine.

### Reusable apps and `AUTH_USER_MODEL`

Reusable apps shouldn’t implement a custom user model. A project may use many apps, and two reusable apps that implemented a custom user model couldn’t be used together. If you need to store per user information in your app, use a ForeignKey or `OneToOneField` to `settings.AUTH_USER_MODEL` as described above.

### Right Choice?

It all ends up on you, your needs.

A project I am working now needed Email Authentication instead of the username-password authentication that Django provides out of the box and we wanted the username field to be removed from my `User` Model. So we used `AbstractUser` to subclass my Custom User Model.

To store more information about Users like the profile picture, bio, and other user-related information we created another Model called `Profile` and we used `OneToOneField` to relate it to Custom User Model.

## Conclusion

It’s always a good idea to use a custom user model if you are still happy with the one provided by Django out of the box.

That’s all for Custom User Model in Django.

Let me know if this post helps you in any way in the comment section below.