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 thepython manage.py createsuperuser
command.is_active
- defaults toTrue
forAbstractBaseUser
, 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
, aCharField
, 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 defaultUser
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.