The Django Rest Custom User Model and Authentication
Tarush Nagpal
Posted on July 22, 2018
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 July 22, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
January 7, 2022