Изображение отсутствует в validated_data - PullRequest
0 голосов
/ 25 июня 2018

Проблема:

Я пытаюсь реализовать сериализатор, который сериализует модель профиля.К сожалению, ключ image и его значение отсутствуют в validated_data, передаваемом методу update() сериализатора.


Настройка:

Это средаЯ проверяю это на:
Django 1.11.4, djangorestframework 3.6.3, Python 3.6.5

Это запрос, который я использую для PUT к соответствующей конечной точке:

curl -vvv \
     -XPUT \
     -H "Authorization:Bearer ${accessToken}" \
     -H "Content-Type:multipart/form-data" \
     -F "user=http://${baseURL}/users/2;type=application/json" \
     -F "image=@${image1};type=image/png" \
     ${url}

Код сериализатора:

from rest_framework import serializers

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Image
        fields = ('image',)

    image = serializers.ImageField(required=True)


class ProfileSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Profile
        fields = (
            'url',
            'user',
            'image',
            )

    image = ImageSerializer(required=False, allow_null=True)

    def update(self, instance, validated_data):
        # The documentation tells me it should now work like this:
        uploaded_image = validated_data.pop('image')
        instance.image = ProfileImage.objects.create(image=uploaded_image)
        return super().update(instance, validated_data)
        # but validated_data.pop('image') raises a KeyError which is logical, 
        # since validated_data does not contain an 'image' key.

Код модели:

from django.db import models
from django.contrib.auth import get_user_model

class Image(models.Model):
    image = models.ImageField(null=True, default=None)

    class Meta:
        abstract = True


class ProfileImage(Image):
    pass


class Profile(models.Model):
    user = models.OneToOneField(get_user_model(), related_name='profile')
    image = models.OneToOneField(ProfileImage, related_name='profile', null=True, default=None)

Когда я устанавливаю точку останова внутри метода update() сериализатора и проверяю validated_data, ключ изображенияпара значений отсутствует, поэтому validated_data.pop('image') (как предложено в документации ) вызывает ошибку KeyError.


Возможный обходной путь?

Могу ли яТем не менее, извлеките изображение из данных запроса, как это, и обновите модель вручную:

def update(self, instance, validated_data):
    uploaded_image = self.context.get('request').data.get('image')
    instance.image = ProfileImage.objects.create(image=uploaded_image)
    return super().update(instance, validated_data)

Однако, это мне кажется довольно хакерским, так как я предполагаю, что должен быть какой-то способ заставить изображение присутствовать в validated_data.


Вопрос (ы):

  • Является ли предлагаемый ручной методcceptable или это плохой взлом?
  • Почему пара значений ключа изображения отсутствует в validated_data?
  • Должна ли она присутствовать?

ЧтоЯ уже пробовал:

Я реализовал переопределение validate() в ProfileSerializer, проверил attrs, которые были переданы ему, изображения там не было.

Я реализовал validate_image() как в ProfileSerializer, так и в ImageSerializer, ни один из которых не был вызван.

Я реализовал validate() и update() переопределение в ImageSerializer, ни один из которых не был вызван.

Ответы [ 2 ]

0 голосов
/ 25 июня 2018

Проблема заключалась в том, что имя image в запросе не совпадало с именем вложенного поля image.image.

Поскольку имя поля не совпадает, Serializer.get_value() возвращает пустое значение ,
что приводит к Serializer.to_internal_value() пропуску поля полностью .

По сути, часть тела просто молча игнорировалась.

Чтобы заставить его работать, мне пришлось изменить запрос на:

curl -vvv \
     -XPUT \
     -H "Authorization:Bearer ${accessToken}" \
     -H "Content-Type:multipart/form-data" \
     -F "user=http://${baseURL}/users/2;type=application/json" \
     -F "image.image=@${image1};type=image/png" \
     ${url}
0 голосов
/ 25 июня 2018

Из Документация Django Rest Framework :

По умолчанию вложенные сериализаторы доступны только для чтения.Если вы хотите поддерживать операции записи во вложенном поле сериализатора, вам нужно создать методы create () и / или update (), чтобы явно указать, как следует сохранять дочерние отношения.

В вашем примере вы должны обновить связанный объект вручную в вашем update методе:

def update(self, instance, validated_data):
    if 'image' in validated_data:
        instance.image.image = validated_data.pop('image')
    ...

    instance.save()
    return instance
...