Проблема с объединением CustomUser и Profile в одну конечную точку в django

У меня есть модель CustomUser и две отдельные модели для профиля двух типов пользователей. Я пытаюсь объединить атрибут CustomUser и один из Profile в одну конечную точку, из которой пользователь может видеть/обновлять/удалять пользователя/профиль. Например, есть 2 типа пользователей, доктор и пациент. Поэтому если пользователь является доктором, то конечная точка будет возвращать атрибуты CustomUser+DoctorProfile и то же самое для пациента CustomUser+PatientProfile. Ниже приведен код. Я объясню проблему в кодовой базе с комментариями. Я буду очень признателен за любые предложения. Следует упомянуть, что я разделил файл models.py на 3 разные папки и импортировал их все в __init__.py папку models.

Модель пользователя:

class CustomUser(AbstractBaseUser, PermissionsMixin):

    class Types(models.TextChoices):
        DOCTOR = "DOCTOR", "Doctor"
        PATIENT = "PATIENT", "Patient"

    # what 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):
    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()}'

Serializer:

class DoctorProfileFields(serializers.ModelSerializer):
    """To get required attributes from DoctorProfile model"""
    class Meta:
        model = DoctorProfile
        fields = ('doctor_type', 'title', 'date_of_birth', 'registration_number', 'gender', 'city', 'country', )


class DoctorProfileSerializer(serializers.ModelSerializer):
    """Above Serializer is used in a new attribute profile. So that I can combine the CustomUser and DoctorProfile."""

    profile = DoctorProfileFields(source='*')
    
    """
    if I use source in the above line the serializer returns the json in the
    expected format while I use get method, otherwise it return error saying profile 
    is not an attribute of CustomUser. but for put method the json payload is getting 
    received in a wrong formation. attributes of nested Profile object is getting 
    combined in the same level of Custom user, 
    {"name": "jon", "avatar": null, "doctor_type": "anything"}
    but it has to receive like this
    {"name": "jon", "avatar": null, "profile": {"doctor_type": "anything}}
    """
    
    class Meta:
        model = User
        fields = ('name', 'avatar', 'profile', )
        
    @transaction.atomic
    def update(self, instance, validated_data):
        ModelClass = self.Meta.model
        """print("=======validated_data=========: ", validated_data). I found in this 
        line that the payload is wrong"""
        profile = validated_data.pop('profile', {})
        """print("=======profile=========: ", profile) profile is not in validated data
        that's why 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 

С другой стороны, если я не использую источник, ошибка одинакова для метода get и put.

Вид:

class DoctorProfileAPIView(generics.RetrieveUpdateDestroyAPIView):
    """To get the doctor profile fields and update and delete"""
    serializer_class = DoctorProfileSerializer
    queryset = User.objects.all()

    def get_object(self):
        return get_object_or_404(User, id=self.request.user.id, is_active=True)

После использования источника метод get возвращается в ожидаемом формате:

{
    "name": "Maruf updated again",
    "avatar": null,
    "profile": {
        "doctor_type": null,
        "date_of_birth": null,
        "registration_number": null,
        "city": null,
        "country": null
    }
}

Но проблема заключается в методе Put. Еще одно замечание: при использовании source и не переопределении метода update в сериализаторе, обновляются только атрибуты CustomUser.

Моя задача состоит в том, чтобы получить оба CustomUser+Profile в одной конечной точке. При обновлении CustomUser и Profile будут обновляться в своих собственных таблицах, но через одну и ту же конечную точку. Любая помощь будет очень признательна.

Вернуться на верх