DRF - M2M через сериализатор для ImageField выдает UnicodeDecodeError - PullRequest
1 голос
/ 09 марта 2020

Я хочу сериализовать модель, используя M2M через отношение. Работает нормально для всех других полей, кроме ImageField. Ниже приведены файлы моей модели и сериализатора:

models.py

class Product(models.Model):
    name = models.CharField('Name', max_length=255, null=True, blank=True)
    description = models.TextField('Description', max_length=1000, null=True, blank=True)
    price = models.IntegerField('Price', default=0)
    image = models.ImageField('Product Image', null=True, blank=True)


class Cart(models.Model):
    user = models.CharField('User ID', default="1000", max_length=255)
    items = models.ManyToManyField("Product", through='CartActions', blank=True)
    modified = models.DateField('Last Modified')


class CartActions(models.Model):
    product = models.ForeignKey('Product', on_delete=models.CASCADE)
    cart = models.ForeignKey('Cart', on_delete=models.CASCADE)
    quantity = models.PositiveSmallIntegerField(default=0)

serializers.py

class ProductSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Product
        fields = ['id', 'name', 'description', 'price', 'image']


class CartSerializer(serializers.HyperlinkedModelSerializer):
    items = CartActionsSerializer(source='cartactions_set', many=True)

    class Meta:
        model = Cart
        fields = ['id', 'user', 'items']


class CartActionsSerializer(serializers.HyperlinkedModelSerializer):
    name = serializers.ReadOnlyField(source='product.name')
    price = serializers.ReadOnlyField(source='product.price')
    image = serializers.ReadOnlyField(source='product.image')  # Adding this line gives error

    class Meta:
        model = CartActions
        fields = ['name', 'price', 'image', 'quantity']

Это ошибка, которую я получаю при попадании в API :

UnicodeDecodeError в / store / api / cart /

код utf-8 c не может декодировать байт 0xff в позиции 0: неверный начальный байт

Это пример ответа, который я получаю от /api/products API:

{
    "id": 1,
    "name": "Product 1",
    "description": "This is a sample description",
    "price": 500,
    "image": "http://192.168.43.210:9000/media/sample_product.jpeg"
}

Я перепробовал почти все ссылки в stackoverflow и других сайтах, но я не могу найти точно такую ​​же проблему нигде. Любая помощь очень ценится. Заранее спасибо.

1 Ответ

0 голосов
/ 09 марта 2020

В этом сериализаторе вы не определили сериализаторы полей явно, только упомянутый список полей:

class ProductSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Product
        fields = ['id', 'name', 'description', 'price', 'image']

DRF распознал image как ImageField и применил serializers.ImageField serializer с аргументом use_url:

use_url - Если установлено значение True, то для выходного представления будут использоваться значения строки URL. Если установлено значение False, то строковые значения файла будут использоваться для выходного представления По умолчанию используется значение ключа настроек UPLOADED_FILES_USE_URL, которое равно True, если не указано иное.

Таким образом, он был сериализован с ProductSerializer в качестве URL-адреса, а не двоичного изображения или имени файла.

В другом сериализаторе вы явно определили сериализатор полей:

class CartActionsSerializer(serializers.HyperlinkedModelSerializer):
    ...
    image = serializers.ReadOnlyField(source='product.image')

ReadOnlyField - это обобщенный c сериализатор, который выводит source в том виде, как он . Таким образом, «product.image» возвращает экземпляр ImageField, который не является URL-адресом или путем - это целый объект со многими атрибутами.

Поэтому попробуйте использовать указанный c сериализатор полей

serializers.ImageField(read_only=True, ...)

или укажите более точный источник c с по умолчанию , чтобы избежать ошибок, если изображение отсутствует

serializers.ReadonlyField(source='product.image.url', default=None, ...)

или получите доступ к этому значению с помощью метода

class CartActionsSerializer(serializers.HyperlinkedModelSerializer):
    ...
    image = serializers.SerializerMethodField()

    def get_image(self, obj):
        return obj.product.image.url
...