通过一个序列化程序更新多个模型数据



请仔细阅读描述,我试图描述我在解决这个问题时遇到的一切。

我有两个模型,User和DoctorProfile。用户模型与DoctorProfile具有OneToOne关系。我正试图通过一个序列化程序来更新这两个模型的数据。我把两个模型组合成一个serilzer,如下所示:

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 

当我用GET方法发送请求时,DoctorProfileSerializer会以所需的方式返回嵌套数据(组合两个模型User和DoctorProfile(。但当我尝试通过这个序列化程序更新这两个模型时,它会返回一个错误,称为User has no field named 'doctor_type'

让我们看看我试图发送的JSON:

{
"name": "Dr. Strange updated twice",
"profile" : {
"doctor_type": "PSYCHIATRIST"
}

}

让我们来看看序列化程序是如何接收JSON:的

{
"name": "Maruf updated trice",
"doctor_type": "PSYCHIATRIST"

}

型号:

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

我怎么知道序列化程序得到了错误的JSON?我在DoctorProfileSerializer中调试了validated_data,结果显示它是一个平面JSON,没有密钥命名的概要文件。

我假设问题出在我在DoctorProfileSerializer中添加的源代码上。但是,如果我不使用源代码,get方法将返回以下错误Got AttributeError when attempting to get a value for field配置文件on serializer (DoctorProfileSerializer).

请让我知道它是否是可解的,如果这样做是一个好方法吗?

好的,如果我的答案太长,很抱歉,但让我尝试逐步回答,

型号:

class DoctorProfile(models.Model):
# everything as it is
# except I feel comfortable using ForeignKey :D
owner = models.ForeignKey(
CustomUser, 
on_delete=models.CASCADE, 
related_name='doctor_profile'
)
# everything as it is
class CustomUser(AbstractBaseUser, PermissionsMixin):
# as it is

序列化程序:

class DoctorProfileSerializer(serializers.ModelSerializer):
"""Serializer for DoctorProfile."""
class Meta(object):
model = DoctorProfile
fields = [
'id',
'doctor_type', 
'title', 
'date_of_birth', 
'registration_number', 
'gender', 
'city', 
'country', 
]
read_only_fields = [
'id',
]
class CustomUserSerializer(serializers.ModelSerializer):
"""Serializer for DoctorProfile."""

# here I'm renaming the related object exactly as the 
# related name you've provided on model
doctor_profile = DoctorProfileSerializer(many=False)
class Meta(object):
model = CustomUser
fields = [
'name', 
'avatar', 
'doctor_profile', 
]
read_only_fields = [
'id',
]
def update(self, instance, validated_data):
# instance is the current row of CustomUser
# validated_data is the new incoming data
# use validated_data.pop('doctor_profile') to extract
# doctor_profile data and do whatever is needed on 
# DoctorProfile model 
# compare them and perform your update method
# as you wish on the DoctorProfile model
# object after updating models, you can query the total
# object again before returning if you want
return updated_object   

视图:

class CustomUserAPIView(RetrieveUpdateAPIView):
"""CustomUserAPIView."""
permission_classes = [IsAuthenticated]
model = CustomUser
serializer_class = CustomUserSerializer
lookup_field = 'id'
#for returning logged in user info only
def get_queryset(self):
return CustomUser.objects.filter(id=self.request.user.id).first()
def update(self, request, *args, **kwargs):
"""Update override."""
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(
instance,
data=request.data,
partial=partial,
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
custom_user_obj = CustomUser.objects.filter(
id=instance.id,
).first()
serializer = CustomUserSerializer(custom_user_obj)
return Response(serializer.data)

运行迁移,并让我知道您是否在GET方法上获得了预期的输出。对于UPDATE方法,如果您遇到任何问题,请告诉我,我会立即更新相应的答案。

为了方便所有与Django Rest Framework相关的文档,请使用以下链接https://www.cdrf.co/

最新更新