Сериализатор DRF принимает вложенную полезную нагрузку JSON как один объект JSON
Пожалуйста, просмотрите описание, я попытался описать все, с чем я столкнулся, пытаясь решить эту проблему.
У меня есть две модели, User и Profile. Я пытаюсь обновить их через один сериализатор. Я объединил две модели в один сериализатор, как показано ниже:
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"
}
Как узнать, что сериализатор получает неправильный JSON? Я отладил validated_data
в DoctorProfileSerializer, и он показывает, что это плоский JSON, нет ключа с именем profile.
Я предполагаю, что проблема связана с источником, который я добавил в DoctorProfileSerializer. Но если я не использую источник, метод get возвращает следующую ошибку
Got AttributeError when attempting to get a value for field
profile 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
queryset = CustomUser.objects.all()
lookup_field = 'id'
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/