Django REST Framework provides basic authentication out of the box, provided with the defaults located in **INSTALLED_APPS** under `settings.py`
To build robust applications however, you will need to more functionality than what it offers;
- Registration
- Account Activation (with activation codes sent via email)
- Password Resets (also sent via email)
- Session expiry with JSON Web Tokens (so that you don't just stay logged in forever)
- and so on...
These features are not built in to DRF, and so we'll have to bring in another package or library for this, [Djoser](https://github.com/sunscrapers/djoser)
To start, run the command `pipenv install djoser djangorestframework-simplejwt`
If you've gotten this far, congratulations! If you're not familiar with basic and intermediate SQL or Python exercises yet, you may have trouble catching up in the following sections. Please consider learning those first or alongside the sections below.
### User Model
We've added authentication (Djoser) and so we will need to create our own concept of a user.
Models are the heart of backend development (not just Django!). While you may know what a car or a person is, your backend (Django) and your database have no idea how this should be structured.
A person can have the following
- Name
- Age
- Birthday
Cars can have them too! But you get my point.
Django already provides a default [User](https://docs.djangoproject.com/en/5.1/ref/contrib/auth/) model, hidden away from sight. We will be overriding and replacing this with our own.
To start, we will need to create a separate app.
In the previous section, we created a simple folder for the **api** app, this will not work for this step.
Instead, make sure you're inside the Django project directory by doing `cd PROJECT_NAME`, in my case, `cd djangobackend`
We will then create an **accounts** app. Run the command `python manage.py startapp accounts`
The best practice when creating Django apps would be naming them in plural form (Books, Records, Posts)
The Books app can hold
- Books
- Pages
- Chapters
Because of this, there is usually no need to make another app for pages and chapters as mentioned above, unless your app is big enough.
With that out of the way, let's begin creating our User model.
We will be creating our own version of a User based on the default one provided by Django [here](https://docs.djangoproject.com/en/5.1/ref/contrib/auth/)with an age and a birthday
```python
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
# Some fields are referenced or copied over from AbstractUser
# first_name, last_name, email, username, and password are among a few of these
birthday = models.DateTimeField(null=True)
age = models.IntegerField(null=True)
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
```
If we CTRL + Click on **AbstractUser**, we can take a deeper look under the hood on Django's default User
By referencing **AbstractUser** on the User we're creating, we're can skip over creating the other fields a user would have (password, email) and the work that comes with how those work under the hood. This is something you will regularly see with Django and will make developing projects faster.
We'll now need to connect our **accounts** app and the **User** model to our existing project
Open the `admin.py` file in the **accounts** app and add the following code block.
This is an important distinction to make especially for starters. Exposing your database without a framework such as Django can allow malicious actors to easily make a mess of everything. Everything Django and DRF provides (authentication, middleware, etc.) serves this purpose.
Carrying on, migrations!
Migrations keep track of what types of kinds of things we wish to store. You previously created a **User** model **(accounts app)**.
The previous command you just ran (`python manage.py makemigrations`) just translated your **User** model (located in `accounts/models.py`) into instructions which will then be used to create the SQL statements under the hood (e.g. `CREATE TABLE USER (username char, password ...)`)
Migrations are very analogous to sandwiches and burgers in a sense, if you decide to add a **grumpy** attribute to your **User**
When you apply these migrations (which we will do shortly), Django reads each migration file in order, starting off with #1 to create the initial **User** model, and then to step #2 to add the **grumpy** field, which under the hood uses SQL Alter (e.g. `ALTER USER ADD grumpy boolean`).
Django's migrations will also let you know if you make changes to your models that might break things (e.g. removing an already added field when you have records for that already).
This is something you should ideally understand with Django and how it interfaces with your database under the hood.
### Apply Migrations
If you've noticed this error in the previous sections, this is because we haven't applied our migrations yet!