Как объединить UserProfile и модель User, которые связаны через отношение OneToOne, в одну конечную точку?

У меня есть пользовательский класс пользователя и класс профиля. Класс профиля имеет отношение OneToOne с пользовательским User. Сериализатор имеет User как Meta модель с добавлением модели профиля в новое поле profile, расширенное на кортеж полей. но когда я пытаюсь получить детальное представление, он возвращает ошибку, говоря, что поле Profile не является атрибутом CustomUser. Я буду благодарен, если вы просмотрите код, который я добавил ниже, и поможете мне в этом.

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

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

Serializer:

class DoctorProfileFields(serializers.ModelSerializer):
    """To get the fields from the DoctorProfile. it will be used in the 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()
    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

Вид:

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)

Я хочу получить json-ответ в детальном представлении, как показано ниже:

{
    "name": the name,
    "avatar": avatar,
    "profile": {
        "doctor_type": "PSYCHIATRIST",
        "title": 1,
        "date_of_birth": 11-11-1990,
        "registration_number": 21547,
    }
}

Может ли кто-нибудь помочь мне в этом? Или есть какой-либо другой подход к проектированию, который соответствует моей цели. Моя цель состоит в том, чтобы информация о пользователе + информация о профиле были объединены в одной конечной точке как целый профиль во фронтенде, из которого пользователь будет видеть/редактировать профиль.

В первую очередь переместите внешний ключ OneToOne в модели CustomUser, добавьте:

owner = models.OneToOneField('DoctorProfile', on_delete=models.CASCADE, related_name='doctor_profile')

и удалить из DoctorProfile:

owner = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name='doctor_profile')

Сделайте все миграции, и теперь вам нужно установить новые данные в db. В сериализаторах вы правильно используете Nested relationships, поэтому добавьте атрибут many, установленный в False:

profile = DoctorProfileFields(many=False)        
Вернуться на верх