• 12 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 3/2/22

Customize the User Model

Set Up the Django Project

Before we dive into how to implement authentication in Django, we first need to set up our project and apps. 

Both the screencast and the course text contain all of the necessary steps to set up the project. You should find that these steps are familiar to you from your previous Django experience!

Now that you have watched the screencast, code along with the steps in the course text to do it yourself.

First, create the project directory and navigate into it.

~/  → mkdir fotoblog && cd fotoblog

 Now set up the Python environment, activate it, and install Django. Also create a  requirements.txt  file using  pip freeze  so you can recreate the environment elsewhere.

~/fotoblog  → python -m venv  ENV
~/fotoblog  → source ENV/bin/activate
(ENV) ~/fotoblog  → pip install django
(ENV) ~/fotoblog → pip freeze > requirements.txt

Our project will contain two apps, one handling authentication and account management called  authentication  , and another which will host our blog post and photo sharing logic  blog .

Let's start the project and create these two apps now.

(ENV) ~/fotoblog  → django-admin startproject fotoblog .
(ENV) ~/fotoblog  → python manage.py startapp authentication
(ENV) ~/fotoblog  → python manage.py startapp blog

Add these apps to the  INSTALLED_APPS in settings.

# fotoblog/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'authentication',
    'blog',
]

Set it up as a Git repository, and make the initial commit.

(ENV) ~/fotoblog  → git init
(ENV) ~/fotoblog  → echo ENV >> .gitignore
(ENV) ~/fotoblog  → echo __pycache__ >> .gitignore
(ENV) ~/fotoblog  → echo db.sqlite3 >> .gitignore
(ENV) ~/fotoblog  → # You may want to add other non-project files and directories to your .gitignore here
(ENV) ~/fotoblog  → git add .
(ENV) ~/fotoblog  → git status
(ENV) ~/fotoblog  → git commit -m  initial commit

The project is now set up. Next , let's configure individual users in Django.

Discover the User Model

By convention, data on an individual user is stored in a model called User. Django provides a default `User` model. This model has many special methods and features, particularly concerning authentication and permissions, that make it seamlessly integrate into the Django framework.  

You can find the default  User  model in  django.contrib.auth.models .

Here's a quick overview of some of the different User  model fields:

  • username  - used to log in.

  • first_name

  • last_name 

  • email

  • password  - this is stored as a hash in the database. Never store raw passwords.

  • is_staff  - a boolean; dictates whether a user can log in to the Django admin site.

  • is_active  - a boolean; it is considered Django best practice to mark users as inactive by setting this attribute toFalse instead of deleting them.

  • is_superuser  - a boolean; superusers are automatically granted all permissions, such as access to the admin site. 

But what if these fields don't fit my use case?

Good question! You may find that you do not require all of these fields. On the other hand, you may want all of them and more!

Luckily, you are not bound to the default model. Let's see how to customize  User  .

Use a Custom User Model

Even if you think that the default  User  model is good enough, you should always implement a custom  User  model in your project, even if it is identical to the default one. 

This is because it is difficult and complicated to migrate to a custom  User  model after your Django site has been set up and your initial migrations have been run. It requires lots of tricky migrations and an in-depth understanding of SQL. Plans change, and clients alter specifications. Save yourself a headache and set up a custom  User  model at the start of your project. 

When using a custom  User  model, Django provides two base classes that you can extend to meet your specific needs:

  • AbstractUser

  • AbstractBaseUser

AbstractUser

The AbstractUser class contains all of the fields and methods that the default  User  does.  

If you think the functionality of the default  User  class alone will meet your needs, then using it as a custom  User  model is as simple as this: 

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

This provides all the features and fields of the default  User  model and the added flexibility of being able to add additional fields and methods to it later.

Say, for instance, you also wanted to store a unique 10-digit account number for each user. To do this, just specify it the same as you would a field on any other model.

class User(AbstractUser):
    account_number =  CharField(max_length=10, unique=True)

If you want to add more fields to the  User  class, you can specify them in the same manner. 

But what if I don't want to use every field provided by the default  User  class? 

Then you extend the  AbstractBaseUser  class instead. Let's have a look at that. 

AbstractBaseUser

The AbstractBaseUser class contains no fields apart from the  password . It also comes with a suite of methods to handle authentication (as does  AbstractUser ). 

When extending the AbstractBaseUser , you must specify all the fields you want to include (except  password  ). There is also some additional configuration required for it to integrate with the Django authentication system. 

The key configurations to implement when using the  AbstractBaseUser  model are:

  • USERNAME_FIELD  - you must set this to the field you want to use when logging in.

  • EMAIL_FIELD  - set to the field that contains a user's primary email, defaults to  'email'  if not specified.

  • REQUIRED_FIELDS  - set this to any fields that must be specified when using the  python manage.py createsuperuser  command.

  • is_active  -  defaults to  True  for  AbstractBaseUser  , but you can add your own field if you want to handle active and inactive users. 

What if I want to use an email address to log in? 

Easy! Just set the constant  USERNAME_FIELD  to the email field. Django requires this to be unique. If you are extending  AbstractUser , you can also then remove the  username field  by setting it to  None  . 

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

class User(AbstractUser):
    email = models.EmailField(unique=True)
    username = None

    USERNAME_FIELD = 'email'

Okay, now that we've gone over some of the different ways to implement a  User  model in Django, let's do it in our app!

Set Up the Django App With a Custom User Model

It is generally better to build off the AbstractUser model as this will automatically integrate with the rest of the Django framework and have the most compatibility with third-party apps.  

We want to include all of the functionality of the default  User  class for our site, so we will extend  AbstractUser  . We will also add two additional fields:

  • an  ImageField  containing a profile photo,

  • and  role , a  CharField , which will differentiate between two types of users on our site, creators and subscribers.

Step 1: Create the  User  model

Add the  User  to the models in  authentication  . 

# authentication/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    CREATOR = 'CREATOR'
    SUBSCRIBER = 'SUBSCRIBER'
  
    ROLE_CHOICES = (
        (CREATOR, 'Creator'),
        (SUBSCRIBER, 'Subscriber'),
    )
    profile_photo = models.ImageField()
    role = models.CharField(max_length=30, choices=ROLE_CHOICES)

Step 2: Configure Django to Use a Custom  User

Out of the box, Django uses the default  User  model for authentication, so you need to tell Django that you want to use your User  model instead. To do that, point  AUTH_USER_MODEL  to the correct model in the settings. When configuring  AUTH_USER_MODEL  , use the notation  '<app-name>.<model-name>'  , giving you: 

# fotoblog/settings.py
AUTH_USER_MODEL = 'authentication.User'

Great, now that you have configured your User  model, you can run the initial migrations. 

Step 3: Run the Initial Migrations

Let’s make the migrations first. When doing this, you may run into this error:

(ENV) ~/fotoblog (master)
→ python manage.py makemigrations
SystemCheckError: System check identified some issues:

ERRORS:
authentication.User.profile_photo: (fields.E210) Cannot use ImageField because Pillow is not installed.
	HINT: Get Pillow at https://pypi.org/project/Pillow/ or run command "python -m pip install Pillow".

Django requires the package  Pillow  in order to use the  ImageField  .  Pillow  is a Python library for processing images. 

Versions of Django older than 3.2 don't automatically install Pillow . If you see this message, you’ll need to install it using  pip  and update the requirements.txt  , then try again.

(ENV) ~/fotoblog (master)
→ pip install Pillow

(ENV) ~/fotoblog (master)
→ pip freeze > requirements.txt 

(ENV) ~/fotoblog (master)
→ python manage.py makemigrations
Migrations for 'authentication':
  authentication/migrations/0001_initial.py
    - Create model User

(ENV) ~/fotoblog (master)
→ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, authentication, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying authentication.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK

Great, you've run the migrations and are set up!

Let's Recap!

  • Django uses the User model to handle authentication. 

  • It is always a good idea to use a custom User model in a project, even if you don't need added functionality, as it makes it much easier to customize it later. 

  • You can extend the AbstractUser to build on the default  User  model. 

  • You can extend AbstractBaseUser for further flexibility and to design all the fields yourself.

Now that you can store users in the database let's try to authenticate them on our site.

Example of certificate of achievement
Example of certificate of achievement