How to Create New User from User_Profile in DRF?

Viewed 48

I am creating a cross-platform application in which the users are - Admin, Instructor, and Student. And for registering a new user privilege is only for admin users, so an admin user can add another admin, instructor, and student. I am trying to make nested serializers by which a UserProfile (AdminProfile, InstructorProfile, or StudentProfile) when created also creates User. I am new to Django and DRF. How can this be done?

serializers.py

from rest_framework import serializers
from .models import User, ProfileAdmin


# # This will have GET method for seeing the users according to the userType.

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'password', 'user_type']
        extra_kwargs = {'password': {'write_only': True}}


class UserProfileSerializer(serializers.ModelSerializer):
    user_account = UserSerializer(many=False)

    class Meta:
        model = ProfileAdmin
        fields = ['email', 'first_name', 'last_name', 'address', 'telNum', 'aliasMailID', 'MSteamsID', 'user_account']

    def create(self, validated_data):
        account_data = validated_data.pop('user_account')
        user = ProfileAdmin.objects.create(**validated_data)
        User.objects.create(**account_data)
        return user

    def update(self, instance, validated_data):
        account_data = validated_data.pop('user_account')
        user_account = instance.user_account

        instance.email = validated_data.get('email', instance.email)
        instance.first_name = validated_data.get('first_name', instance.first_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.address = validated_data.get('address', instance.address)
        instance.telNum = validated_data.get('telNum', instance.telNum)
        instance.aliasMailID = validated_data.get('aliasMailID', instance.aliasMailID)
        instance.MSteamsID = validated_data.get('MSteamsID', instance.MSteamsID)
        instance.save()

        user_account.username = account_data.get('username', user_account.username)
        user_account.user_type = account_data.get('user_type', user_account.user_type)
        return instance

models.py

from django.db import models
from django.contrib.auth.models import AbstractUser, PermissionsMixin, UserManager, AbstractBaseUser
from django.conf import settings
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils.translation import gettext_lazy as _


class CustomAccountManager(UserManager):

    def _create_user(self, username, password, user_type, **extra_fields):
        if not username:
            raise ValueError(_('The Username must be set'))
        if not password:
            raise ValueError('The password must be set')
        if not user_type:
            raise ValueError('The user type must be set')

        username = self.model.normalize_username(username)
        user = self.model(username=username, user_type=user_type, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_user(self, username, password, user_type, **extra_fields):
        if user_type == 'STUDENT' or user_type == 'INSTRUCTOR':
            extra_fields.setdefault('is_staff', False)
            extra_fields.setdefault('is_superuser', False)

        return self._create_user(username, password, user_type, **extra_fields)

    def create_superuser(self, username, password, user_type, **extra_fields):

        # if is_userType == 'Admin'
        if user_type == 'ADMIN':
            extra_fields.setdefault('is_staff', True)
            extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(username, password, user_type, **extra_fields)

class User(AbstractBaseUser, PermissionsMixin):
    USER_TYPE_CHOICES = (
        ('ADMIN', 'admin'),
        ('INSTRUCTOR', 'instructor'),
        ('STUDENT', 'student'),
    )

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )

    user_type = models.CharField(max_length=40, choices=USER_TYPE_CHOICES)
    username = models.CharField(max_length=30, unique=True)
    password = models.CharField(_('password'), max_length=128)

    objects = CustomAccountManager()
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['password', 'user_type']


class ProfileAdmin(User, models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    email = models.EmailField(verbose_name="email", max_length=85, unique=True)
    aliasMailID = models.EmailField(verbose_name="aliasMailID", max_length=85, unique=True, blank=False)
    address = models.TextField()
    MSteamsID = models.EmailField(verbose_name="MSteamsID", max_length=85, unique=True, blank=False)
    telNum = PhoneNumberField(null=False, blank=False, unique=True

views.py

class RegisterUserAPI(generics.GenericAPIView):
    serializer_class = UserProfileSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        return Response({
            "user": UserProfileSerializer(user, context=self.get_serializer_context()).data,

        })

urls.py

from django.conf.urls import url, include
from django.urls import path
from .views import RegisterUserAPI

urlpatterns = [
    path('users/', RegisterUserAPI.as_view(), name="userRegister"),
]

When I run it, I have access to http://localhost:8000/api/users and can see the form to fill the required field, but as soon as I hit POST I get a TypeError:

TypeError at /api/users/
User() got an unexpected keyword argument 'user'
Request Method: POST
Request URL:    http://127.0.0.1:8000/api/users/
Django Version: 3.0
Exception Type: TypeError
Exception Value:    
User() got an unexpected keyword argument 'user'
Exception Location: C:\PyCharm\MobileLearningApplication\venv\lib\site-packages\django\db\models\base.py in __init__, line 500
Python Executable:  C:\PyCharm\MobileLearningApplication\venv\Scripts\python.exe
Python Version: 3.8.9
Python Path:    
['C:\\PyCharm\\MobileLearningApplication\\MobileLearningApplication',
 'C:\\Python\\python38.zip',
 'C:\\Python\\DLLs',
 'C:\\Python\\lib',
 'C:\\Python',
 'C:\\PyCharm\\MobileLearningApplication\\venv',
 'C:\\PyCharm\\MobileLearningApplication\\venv\\lib\\site-packages']
Server time:    Sat, 9 Oct 2021 09:37:44 +0000

error image

0 Answers
Related