Единый API обновления и удаления для двух моделей, связанных отношением OneToOne в Django Rest Framework
Я много искал здесь и, вероятно, исчерпал все ответы, и все еще не нашел решения моей конкретной проблемы, которая заключается в том, чтобы сделать API, который обновляет/удаляет из обеих моделей, и я получаю следующую ошибку:
The
.update()method does not support writable nested fields by default. Write an explicit
.update()method for serializer
user_profile.serializers.UserSerializer, or set
read_only=True on nested serializer fields.
В данном конкретном случае это происходит, когда я пытаюсь обновить поле из модели user_profile
Я разделил свой проект Django на несколько приложений/папок, каждая модель находится в своей собственной папке.
У меня есть приложение user и приложение user_profile каждое со своими собственными моделями.
модель пользователя - это, по сути, AbstractUser, сидящий в своем собственном приложении
модель user_profile выглядит следующим образом:
class UserProfile(models.Model): user = models.OneToOneField(to=User, on_delete=models.CASCADE, related_name='userprofile') location = models.CharField(blank=True, max_length=30) created_time = models.DateTimeField(auto_now_add=True) updated_time = models.DateTimeField(auto_now=True)
Сериализаторы следующие:
`class UserProfileCrudSerializer(serializers.ModelSerializer): class Meta: модель = UserProfile поля = ('location', 'created_time', 'updated_time')
class UserSerializer(serializers.ModelSerializer): profile = UserProfileCrudSerializer(source='userprofile', many=False)
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'profile')
def update(self, instance, validated_data):
userprofile_serializer = self.fields['profile']
userprofile_instance = instance.userprofile
userprofile_data = validated_data.pop('userprofile', {})
userprofile_serializer.update(userprofile_instance, userprofile_data)
instance = super().update(instance, validated_data)
return instance`
а мое мнение таково:
`class RetrieveUpdateView(RetrieveUpdateAPIView): serializer_class = UserSerializer queryset = User.objects.all()
def get_object(self):
return self.request.user`
Когда я делаю GET, я получаю следующий ответ без каких-либо проблем:
{ "username": "blue", "email": "bluebear@bluebear.com", "first_name": "Blue", "last_name": "Bear", "profile": { "location": "London", "created_time": "2023-02-03T00:39:15.149924Z", "updated_time": "2023-02-03T00:39:15.149924Z" } }
и я делаю запрос на исправление следующим образом:
{ "profile": { "location": "Paris" } }
Сейчас у меня нет проблем с обновлением имени пользователя, email, first_name и last_name, которые приходят из AbstractUser, но я получаю вышеуказанную ошибку, когда пытаюсь исправить местоположение, которое находится в модели UserProfile.
Я просмотрел множество подобных решений в Интернете, но ни одно из них не относится к моей конкретной ситуации.
Метод .update() по умолчанию не поддерживает записываемые вложенные поля. Напишите явный метод .update() для serializeruser_profile.serializers.UserSerializer, или установите read_only=True для вложенных полей сериализатора.
.
В сообщении уже показано, вам нужно явно написать метод обновления для записываемого вложенного сериализатора, который документирован здесь https://www.django-rest-framework.org/topics/writable-nested-serializers/ или вы можете использовать другой модуль, который также упоминается в документации https://github.com/beda-software/drf-writable-nested.
Ваш подход уже правильный, но в вашем коде есть опечатка и неправильный отступ:
class UserSerializer(serializers.ModelSerializer):
profile = UserProfileCrudSerializer(source='userprofile', many=False)
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name', 'profile')
def update(self, instance, validated_data):
# update is a method of serializer not serializer.Meta
userprofile_serializer = self.fields['profile']
userprofile_instance = instance.userprofile
# should be 'profile' here instead of 'userprofile' as you defined in serializer
userprofile_data = validated_data.pop('profile', {})
userprofile_serializer.update(userprofile_instance, userprofile_data)
instance = super().update(instance, validated_data)
return instance