Djoser override UserCreateSerializer not creating model instance

49 views Asked by At

I've made modifications to the UserCreateSerializer provided by Djoser. Within the perform_create method, I'm attempting to create instances of the UserProfile and AddressDetails models. While the server appears to be functioning correctly, it seems that the data is not persisting as expected. I'm seeking guidance on identifying and rectifying any errors in this process. How would you suggest addressing this issue?

accounts.serializers.py

from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model
from rest_framework import serializers
from django.db import transaction
from django.db.utils import IntegrityError
from django.contrib.auth.password_validation import validate_password
from .models import AddressDetails, UserProfile

User = get_user_model()

class UserCreateSerializer(UserCreateSerializer):
    address_line_one = serializers.CharField(write_only=True)
    address_line_two = serializers.CharField(write_only=True)
    address_line_three = serializers.CharField(write_only=True)
    province = serializers.CharField(write_only=True, required=True)
    barangay = serializers.CharField(write_only=True, required=True)
    city = serializers.CharField(write_only=True, required=True)
    zip_code = serializers.CharField(write_only=True, required=True)
    first_name = serializers.CharField(write_only=True, required=True)
    middle_name = serializers.CharField(write_only=True, required=True)
    last_name = serializers.CharField(write_only=True, required=True)
    date_of_birth = serializers.DateField()
    gender = serializers.CharField(write_only=True, required=True)
    relationship_status = serializers.CharField(write_only=True, required=True)
    phone_number = serializers.CharField(write_only=True, required=True)

    class Meta(UserCreateSerializer.Meta):
        model = User
        fields = (
            "id",
            "email",
            "user_role",
            "password",
            "address_line_one",
            "address_line_two",
            "address_line_three",
            "province",
            "barangay",
            "city",
            "zip_code",
            "first_name",
            "middle_name",
            "last_name",
            "date_of_birth",
            "gender",
            "relationship_status",
            "phone_number"
        )
    
    @transaction.atomic
    def perform_create(self, validated_data):
        address_line_one = validated_data.pop("address_line_one")
        address_line_two = validated_data.pop("address_line_two")
        address_line_three = validated_data.pop("address_line_three")
        province = validated_data.pop("province")
        barangay = validated_data.pop("barangay")
        city = validated_data.pop("city")
        zip_code = validated_data.pop("zip_code")
        first_name = validated_data.pop("first_name")
        middle_name = validated_data.pop("middle_name")
        last_name = validated_data.pop("last_name")
        date_of_birth = validated_data.pop("date_of_birth")
        gender = validated_data.pop("gender")
        relationship_status = validated_data.pop("relationship_status")
        phone_number = validated_data.pop("phone_number")

        with transaction.atomic():
            user = User.objects.create_user(**validated_data)
            
            address_details = AddressDetails.objects.create(
                address_line_one = address_line_one,
                address_line_two = address_line_two,
                address_line_three = address_line_three,
                province = province,
                barangay = barangay,
                city = city,
                zip_code = zip_code
            )

            UserProfile.objects.create(
                user = user,
                first_name = first_name,
                middle_name = middle_name,
                last_name = last_name,
                date_of_birth = date_of_birth,
                gender = gender,
                relationship_status = relationship_status,
                phone_number = phone_number,
                address_details = address_details
            )

        return user
    
    def validate_password(self, value):
        user = self.user if self.user else self.Meta.model()

        try:
            validate_password(value, user)
        except serializers.ValidationError as e:
            serializer_error = serializers.as_serializer_error(e)
            raise serializers.ValidationError(
                {"password": serializer_error[api_setting.NON_FIELDS_ERRORS_KEY]}
            )

        return value

accounts.models.py

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models #type: ignore
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField #type: ignore

# Create your models here.
class UserAccountManager(BaseUserManager):
    def create_user(self, email, user_role, password=None, **extra_fields):
        if not email:
            raise ValueError("Users must have an email address.")

        if not user_role:
            raise ValueError("Users must have a user role.")
        
        email = self.normalize_email(email)
        user = self.model(email=email, user_role=user_role, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    def create_superuser(self, email, user_role="admin", password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_admin", True)
        extra_fields.setdefault("is_active", 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_admin") is not True:
            raise ValueError(_("Superuser must have is_admin=True."))
        if extra_fields.get("is_superuser") is not True:
            raise ValueError(_("Superuser must have is_superuser=True."))
        return self.create_user(email, user_role, password, **extra_fields)

class UserAccount(AbstractBaseUser, PermissionsMixin):
    USER_ROLES = (
        ("resident", "Resident"),
        ("healthworker", "Health Worker"),
        ("admin", "Admin")
    )

    email = models.EmailField(_("email address"), unique=True)
    user_role = models.CharField(max_length=100, choices=USER_ROLES)
    is_staff = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(default=timezone.now)

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["user_role",]

    objects = UserAccountManager()

    def __str__(self):
        return self.email
    
    def has_perm(self, perm, obj=None):
        return True
    
    def has_module_perms(self, app_label):
        return True
    
    def save(self, *args, **kwargs):
        if self.user_role == "admin":
            self.is_staff = True
            self.is_admin = True
        elif self.user_role == "healthworker":
            self.is_staff = True
            self.is_admin = False
        else:
            self.is_staff = False
            self.is_admin = False
        
        super().save(*args, **kwargs)


class AddressDetails(models.Model):
    address_line_one = models.CharField(max_length=150, blank=True,)
    address_line_two = models.CharField(max_length=150, blank=True,)
    address_line_three = models.CharField(max_length=150, blank=True,)
    province = models.CharField(max_length=150, blank=True,)
    barangay = models.CharField(max_length=150, blank=True,)
    city = models.CharField(max_length=150, blank=True,)
    zip_code = models.CharField(max_length=5, blank=True,)
    
class UserProfile(models.Model):
    GENDER_CHOICES = (
        ("F", "Female",),
        ("M", "Male",),
        ("U", "Unsure",),
    )
    user = models.OneToOneField(UserAccount, on_delete=models.CASCADE)
    first_name = models.CharField(max_length=150,)
    middle_name = models.CharField(max_length=150,)
    last_name = models.CharField(max_length=150,)
    date_of_birth = models.DateField()
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES,)
    relationship_status = models.CharField(max_length=50,)
    phone_number = PhoneNumberField()
    address_details = models.OneToOneField(AddressDetails, on_delete=models.CASCADE)
0

There are 0 answers