Why is username required when I set email as username

I have a Vue front end and Django backend

I am using a custom user model:

from django.utils import timezone
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

today = timezone.now()

class UserManager(BaseUserManager):
    def create_user(self, email, password, username=None, role=None):
        user = self.model(email=self.normalize_email(email))
        user.created_at = today
        return user

    def create_superuser(self, email, password, role, username=None):
        user = self.model(email=self.normalize_email(email))
        user.role = role
        user.is_staff = True 
        user.is_active = True
        user.is_superuser = True
        return user

class User(AbstractBaseUser, PermissionsMixin):
    EM = 'EM'
    SM = 'SM'
    DH = 'DH'
    ROLES = [
        (EM, 'Executive Management'),
        (SM, 'Senior Management'),
        (DH, 'Department Head'),
    objects = UserManager()
    role = models.CharField(max_length=2, choices=ROLES, default=US, blank=True)
    username = models.CharField(max_length=100, unique=True, blank=True, null=True)
    email = models.EmailField(max_length=255, unique=True)
    slug = models.SlugField()
    is_active = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    email_verified_at = models.DateTimeField(auto_now=False, null=True, blank=True)
    confirmed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")

    class Meta:
        verbose_name = "User"
        verbose_name_plural = "Users"
        ordering = ["username"]
        db_table = "users"

    def get_absolute_url(self):
        return f"{self.slug}"

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['role']

I am trying to get an authentication token but the response I get is username is required. Why is it required if I set the username field to email?

I am using this code top get the token:

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response

class CustomAuthToken(ObtainAuthToken):

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data,
                                           context={'request': request})
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        return Response({
            'token': token.key,
            'user_id': user.pk,
            'email': user.email

Hey there!

Are you’re even using the username field? If you don’t want the username field, you can just set it to None on the class, and then set USERNAME_FIELD = "email" on the class as well.

This is not related, but this line may not work as you expect:

You’re using this variable value inside your functions, and this value is only calculated once, when your server starts and imports this module. You should either:

  • move this variable to the function that uses it;
  • add the auto_now_add on the created_at field from your User model

I want to use the username field later. I set USERNAME_FIELD to email in my code

Ok, does that solves the issue?

no because I had it like that from the start

This part is the cause of the headache

The obtain_auth_token view will return a JSON response when valid username and password fields are POSTed to the view using form data or JSON:

Alright, can you post the traceback here then?

There is no traceback sir I am using a Vue front end calling the api

Ok, You’re probably receiving a 400 BAD REQUEST on your frontend.
It looks like you’re using the serializer_class from the ObtainAuthToken view.

Looking at the source code of the AuthTokenSerializer it expects a username field.
How does your POST data looks like?

I am sending an email and password. I know it’s expecting a username and that is my whole problem. How do I change it so it asks for an email. I thought that is what I did when I put in the model that the username must be the email.

You can define a custom serializer_class on your view that inherits from the AuthTokenSerializer and sets the source attribute on the username field to email.

how do I do that please I am new to Django and really not sure on how to do that

Here are the docs for:
source attribute;

The target serializer to inherit is: rest_framework.authtoken.serializers.AuthTokenSerializer

Ok thank you I will have a look