Search code examples
python-3.xdjangodjango-modelsdjango-rest-frameworkdjoser

using custom model fo django djoser


i am creating api endpoints for user management using Djoser and i want to use a custom model to create user and login i only want to use email.

the user entity given to me does not have a username field

below i will share the various settings i have set up for my apps

#accounts/model.py
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.

class CustomUser(AbstractUser):
    username = None
    email = models.EmailField(unique=True)
    REQUIRED_FIELDS = ['first_name', 'last_name']
    USERNAME_FIELD = 'email'

    def __str__(self):
        return self.email

My serializer file

#accounts/serializers.py
from djoser.serializers import UserCreateSerializer, UserSerializer
from rest_framework import serializers
from rest_framework.fields import CurrentUserDefault
from .models import CustomUser

class UserCreateSerializer(UserCreateSerializer):
    class Meta:
        model = CustomUser
        fields = ['id', 'email', 'first_name', 'last_name']

#settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        # 'rest_framework_simplejwt.authentication.JWTAuthentication',
        'rest_framework.authentication.TokenAuthentication',

    ),
    'DEFAULT_PERMISSIONS_CLASSES': (
        'rest_framework.permissions.IsAuthenticated'
    )
}

AUTH_USER_MODEL = 'accounts.CustomUser'

DJOSER = {
    'LOGIN_FIELD': 'email',
    'USER_CREATE_PASSWORD_RETYPE': True,
    'SERIALIZERS': {
        'user_create': 'accounts.serializers.UserCreateSerializer',
        'user': 'accounts.serializers.UserCreateSerializer',
        # 'current_user': 'accounts.serializers.CurrentUserSerializer'
    }

when i try to register user i get

TypeError at /auth/users/

create_user() missing 1 required positional argument: 'username'

Request Method:     POST
Request URL:    http://127.0.0.1:8000/auth/users/
Django Version:     3.1
Exception Type:     TypeError
Exception Value:    

create_user() missing 1 required positional argument: 'username'

Exception Location:     /home/femiir/.virtualenvs/codegarage/lib/python3.8/site-packages/djoser/serializers.py, line 73, in perform_create
Python Executable:  /home/femiir/.virtualenvs/codegarage/bin/python
Python Version:     3.8.5

please what i my doing wrong ?


Solution

  • You need to have a custom user manager, probably something like this:

    from django.contrib.auth.base_user import BaseUserManager
    
    
    class MyUserManager(BaseUserManager):
        def create_user(self, email, password=None, **extra_fields):
            """
            Creates and saves a User with the given email, first name,
            last name and password.
            """
            if not email:
                raise ValueError("Users must have an email address")
    
            user = self.model(
                email=self.normalize_email(email),
                **extra_fields,
            )
    
            user.set_password(password)
            user.save(using=self._db)
            return user
    
        def create_superuser(self, email, password=None, **extra_fields):
            """
            Creates and saves a superuser with the given email, first name,
            last name and password.
            """
            user = self.create_user(
                email,
                password=password,
                **extra_fields,
            )
            user.is_admin = True
            user.save(using=self._db)
            return user
    

    And in your custom user model:

    class CustomUser(AbstractBaseUser):
        # [...]
        objects = MyUserManager()
        # [...]
    

    I've taken the code from the django documentation about customizing the User model. They provide an example using the email as the username field (which is what you want).

    You may keep the inheritance from AbstractUser but if you do not need most of the things that are in that model, you can also inherit your model from AbstractBaseUser, as in the example.