请仔细阅读描述,我试图描述我在解决这个问题时遇到的一切。
我有两个模型,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/