loading...

The Django Rest Custom User Model and Authentication

callmetarush profile image Tarush Nagpal ・2 min read

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

    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

    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

    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

    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

    from rest_auth.registration.views import RegisterView

    class CustomRegisterView(RegisterView):
        queryset = User.objects.all()

Finally update the settings.py to apply these

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

Posted on by:

callmetarush profile

Tarush Nagpal

@callmetarush

College student by day, freelancer by night

Discussion

pic
Editor guide
 

it is patially working. It didn't pass any values of new feilds. check this plzzz

stackoverflow.com/questions/615595...

 

Thanks for this nice tutorial! Can you provide some info on how to update fields on the registration serializer (CustomRegisterSerializer) so it won't display the inherited fields from the parent class in the browsable API.

 

1) I have an existing user table called user_master. It has more than 10000 existing records which was moved from the legacy system. Instead of using django's defult user table, can I use this table?
2)Second question is can I avoid using django model for managing users. means I will insert the users directly by calling Postgresql function. I want the django login check using the same user_master table.

 

great post Tarush! would you make a post explaining how to do the same but with having the user profile as a separate model?

 

It is currently a separate model

 

I'm sorry but I just see one model here:
class User(AbstractBaseUser)

 

Hi Tarush,

   Would you show me, how to integrate react js with django ?
 

Hi! There are multiple ways to do so, In the scenario for this post I had deployed my django app as a REST API and then made POST/GET Requests from my react app to django, It's makes communications very simple and straight forward.

 

Have you used nginx to integrate fronend and backend

I think you're a little confused, nginx is a web server which mostly helps us while we're hosting it somewhere. To "integrate" frontend and backend you just need to make POST/GO requests from the frontend to the backend

 

Great Article. Thanks for sharing.
Instead of username being email address what if you wanted to use phone number ?
What other changes would one need to make ? Thanks

 

Thanks for the explanation.
can you tell me how can I add an image filed in it.
I need to upload user's profile picture

 

Just check out the Django documentation, they have a great example and explanation.
docs.djangoproject.com/en/2.2/

 

You should make it clear, that you will use which library for a faster reading =)
Not bad post anyway!

 

hi Tarush i need your help with one of my Drf react project i just wanted to tweak a few things but i am not able to do that because i am a newbie to Django rest framework

 

Hey! Drop me a mail

 

Hi Tarush,
Would you kindly assist in creating a login Serializer ,model and View for users to login with token authentication? But Custom based Models. I'm a bit stuck somewhere