Skip to content
thesarfo

Note

Extending the User Model

Why you'd extend Django's built-in User model (e.g. to make email unique), and the migration/errors that come with doing it mid-project.

views 0

Every Django app comes with its in-built authentication system which also has its own tables that are created in the database. If you look at the auth_user table in your database you can see the users that have been created in your app and also the level of access they have and how to also limit such access. You can also customize that table and add more columns for more users.

The user authentication system in django is really good, but somethimes we need to store extra information about the user. In this case we have two options…one option is to use inheritance to extend the user model. So you can create another model called ‘AppUser’ that will extend the user model. The other option is to create a ‘Profile’ model and in this model we add a one-to-one relationship between it and the User model. So the profile model is composed of a user model.

Now lets say in our user model, our email field isnt unique, which means we can have multiple users with the same email. This is not really practical, so in this situation we need to extend the user model. We can create an app called “core” and install it, and create a new model that extends the User model that we had before. see below

#core apps.py
from django.db import models
from django.contrib.auth.models import AbstractUser #the abstract user is the user we previously had
# Create your models here.
class User(AbstractUser):
email = models.EmailField(unique=True) # now we have made the email unique

After doing this, you will get some errors, but you can fix it by creating a new setting in your settings.py file. see below

settings.py
AUTH_USER_MODEL = 'core.User' # it has to be exactly as the variable is spelled. and "core" is the name of the new app we created which will house our new User model

This tells django that we now want to use the extended version of our user model instead of the previous one we had.

And then if you get a different error, it’ll probably be because there is another model that is referencing the previous User model. you can fix it by referencing the new User model.

from django.conf import settings # import settings
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
class LikedItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) # reference the new user model
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()

The thing is, usually you will get a lot of errors if you try to extend your model in the middle of development. So it is best practice to create the app and then create the extended model, and then dont do anything in that model. so later you can easily switch. something like this

class User(AbstractModel):
pass

Since this errors are too much, our option will be to drop and recreate our database. Then migrate your database again and create a new admin user. and then register the extended user model. see below

core/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.contenttypes.admin import GenericTabularInline
from tags.models import TaggedItem
from .models import User
# Register your models here.
@admin.register(User)
class UserAdmin(BaseUserAdmin):
'''we've done the below because we want to include "username", "password1", "password2", "email", "first_name", "last_name" when creating a user'''
add_fieldsets = (
(None, {
"classes": ("wide",),
"fields": ("username", "password1", "password2", "email", "first_name", "last_name"),
}),
)
class TagInline(GenericTabularInline):
autocomplete_fields = ['tag']
model = TaggedItem