Please go through the description, I tried to describe everything i've encountered while trying to solve this issue.
I have two models, User and DoctorProfile. User model has OneToOne relation with DoctorProfile. I'm trying to update data of both model through one serializer. I've combined two models into one serilzer like below:
class DoctorProfileFields(serializers.ModelSerializer):
"""this will be used as value of profile key in DoctorProfileSerializer"""
class Meta:
model = DoctorProfile
fields = ('doctor_type', 'title', 'date_of_birth', 'registration_number', 'gender', 'city', 'country', )
class DoctorProfileSerializer(serializers.ModelSerializer):
"""retrieve, update and delete profile"""
profile = DoctorProfileFields(source='*')
class Meta:
model = User
fields = ('name', 'avatar', 'profile', )
@transaction.atomic
def update(self, instance, validated_data):
ModelClass = self.Meta.model
profile = validated_data.pop('profile', {})
ModelClass.objects.filter(id=instance.id).update(**validated_data)
if profile:
DoctorProfile.objects.filter(owner=instance).update(**profile)
new_instance = ModelClass.objects.get(id = instance.id)
return new_instance
When I send request with GET
method, the DoctorProfileSerializer returns nested data(Combining two models User and DoctorProfile) in the desired fashion.
But when I try to update both models through this serializer, it returns error saying User has no field named 'doctor_type'
.
Let's have a look at the JSON i'm trying to send:
{
"name": "Dr. Strange updated twice",
"profile" : {
"doctor_type": "PSYCHIATRIST"
}
}
Let's have a look at how the serializer is receiving the JSON:
{
"name": "Maruf updated trice",
"doctor_type": "PSYCHIATRIST"
}
Models:
class CustomUser(AbstractBaseUser, PermissionsMixin):
class Types(models.TextChoices):
DOCTOR = "DOCTOR", "Doctor"
PATIENT = "PATIENT", "Patient"
#Type of user
type = models.CharField(_("Type"), max_length=50, choices=Types.choices, null=True, blank=False)
avatar = models.ImageField(upload_to="avatars/", null=True, blank=True)
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = CustomBaseUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'type'] #email is required by default
def get_full_name(self):
return self.name
def __str__(self):
return self.email
class DoctorProfile(models.Model):
"""Model for Doctors profile"""
class DoctorType(models.TextChoices):
"""Doctor will choose profession category from enum"""
PSYCHIATRIST = "PSYCHIATRIST", "Psychiatrist"
PSYCHOLOGIST = "PSYCHOLOGIST", "Psychologist"
DERMATOLOGIST = "DERMATOLOGIST", "Dermatologist"
SEXUAL_HEALTH = "SEXUAL HEALTH", "Sexual health"
GYNECOLOGIST = "GYNECOLOGIST", "Gynecologist"
INTERNAL_MEDICINE = "INTERNAL MEDICINE", "Internal medicine"
DEVELOPMENTAL_THERAPIST = "DEVELOPMENTAL THERAPIST", "Developmental therapist"
owner = models.OneToOneField(
CustomUser,
on_delete=models.CASCADE,
related_name='doctor_profile'
)
doctor_type = models.CharField(
_("Profession Type"),
max_length=70,
choices=DoctorType.choices,
null=True,
blank=False
)
title = models.IntegerField(_('Title'), default=1, choices=TITLES)
date_of_birth = models.DateField(null=True, blank=False)
gender = models.IntegerField(_('Gender'), default=1, choices=GENDERS)
registration_number = models.IntegerField(_('Registration Number'), null=True, blank=False)
city = models.CharField(_('City'), max_length=255, null=True, blank=True)
country = models.CharField(_('Country'), max_length=255, null=True, blank=True)
def __str__(self):
return f'profile-{self.id}-{self.title} {self.owner.get_full_name()}'
How do I know that the serializer is getting wrong JSON? I debugged the validated_data
in the DoctorProfileSerializer and it's showing that it's a flat JSON, there's no key named profile.
I'm assuming the problem is with the source that I've added in the DoctorProfileSerializer. But if I don't use the source the get method returns the following error
Got AttributeError when attempting to get a value for field
profile on serializer (DoctorProfileSerializer).
Please let me know if it's solvable also if it's a good approach to do it this way?