The Django Rest Custom User Model and Authentication
Tags: django, python, djangorest
Published: 2018-07-22 09:39:01

---
title: The Django Rest Custom User Model and Authentication
published: true
description: A small tutorial on building a custom user authentication with Django
tags: Django, Python, Django Rest
---

I was recently building a website for one of my clients by using the Django rest + React framework ( which is beautiful by the way ) and encountered a problem. 

# The Problem

If any of you have worked with Django Rest you'll know the multiple issues that pop up while making a custom user model, and specifically how the changes you make don't reflect upon a save. 

I'll show you the best way (in my opinion) to build a custom user model in DRF (Django Rest Framework), without a username.

## Step 1 

Create an app called user ( Or whatever you want to call it ) and in the models.py make a User model which extends AbstractBaseUser

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

    class User(AbstractBaseUser):

        username = None
        email = models.EmailField(_('email address'), unique=True)
        name = models.CharField(max_length=100)
        date_of_birth = models.DateField(default=datetime.date.today)
        
        USERNAME_FIELD = 'email'
        REQUIRED_FIELDS = [ 'date_of_birth','name' ]
        
        def __str__(self):              # __unicode__ on Python 2
            return self.email
```

## Step 2

And now we add a very important line in the model

```python
    objects = UserManager()
```

This basically tells Django how it's supposed to store the Object and with what attributes depending on permissions.

## Step 3

We add the usermanager

```python
    class UserManager(BaseUserManager):
    
    use_in_migrations = True

    def create_user(self, email, name, date_of_birth, password=None):
        user = self.model(
            email=self.normalize_email(email),
            date_of_birth=date_of_birth,
            name=name,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_staffuser(self, email, name, date_of_birth, password):
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,         
            name=name,
        )
        user.staff = True
        user.save(using=self._db)
        return user

    def create_superuser(self, email, name, date_of_birth, password):
        user = self.create_user(
            email,
            password=password,
            date_of_birth=date_of_birth,
            name= "True",
        )
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user
```

## Step 4

Build the CustomRegisterSerializer

```python
    from rest_auth.registration.serializers import RegisterSerializer
    class CustomRegisterSerializer(RegisterSerializer):
    
        email = serializers.EmailField(required=True)
        password1 = serializers.CharField(write_only=True)
        name = serializers.CharField(required=True)
        date_of_birth = serializers.DateField(required=True)
    
        def get_cleaned_data(self):
            super(CustomRegisterSerializer, self).get_cleaned_data()
    
            return {
                'password1': self.validated_data.get('password1', ''),
                'email': self.validated_data.get('email', ''),
                'name': self.validated_data.get('name', ''),
                'date_of_birth': self.validated_data.get('date_of_birth', ''),
            }

    class CustomUserDetailsSerializer(serializers.ModelSerializer):

        class Meta:
            model = User
            fields = ('email','name','date_of_birth')
            read_only_fields = ('email',)
```

Create the custom view which just has all user objects as a query set

```python
    from rest_auth.registration.views import RegisterView
    
    class CustomRegisterView(RegisterView):
        queryset = User.objects.all()
```

Finally update the settings.py to apply these

```python
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_AUTHENTICATION_METHOD = 'email'

ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_USER_EMAIL_FIELD = 'email'
ACCOUNT_LOGOUT_ON_GET = True

AUTH_USER_MODEL = 'users.User'

REST_AUTH_SERIALIZERS = {
    "USER_DETAILS_SERIALIZER": "users.serializers.CustomUserDetailsSerializer",
}
REST_AUTH_REGISTER_SERIALIZERS = {
    "REGISTER_SERIALIZER": "users.serializers.CustomRegisterSerializer",
}
```

And just add the view to the URL and you're good to go!

I honestly believe that the Django Rest + React stack is one of the best ones in the game right now, but the Django Rest Framework does need a little bit more work to make it perfect for most developers.

Hit me up if you need help! Or have some projects that need people to work with :D