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)