如何在请求中添加多个 base64 编码的图像

How to add multiple base64 encoded images in a request

提问人:Maxim K 提问时间:11/6/2023 更新时间:11/7/2023 访问量:40

问:

我想发出 POST 请求来创建机器人,同时我想传输几个以 base64 编码的photo_examples图像。 默认情况下,使用 Base64ImageField 时,只能添加一张图片,我需要添加几张。 我试图查看互联网上的其他项目,但我没有找到如何实现它的解决方案。

models.py

class Bot(models.Model):
    """Bot Model."""
    name = models.CharField(
        'Название',
        max_length=100
    )
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name='Автор',
    )
    description = models.TextField(
        'Описание'
    )
    categories = models.ManyToManyField(
        Category,
        through='CategoryBot',
        related_name='bots',
        verbose_name='Категории',
    )
    main_photo = models.ImageField(
        'Фото',
        upload_to='uploads/main/%Y/%m/%d/',
    )
    price = models.DecimalField(
        'Цена',
        max_digits=8,
        decimal_places=0
    )
    is_special_offer = models.BooleanField(
        'Спецпредложение',
        default=False
    )

    class Meta:
        ordering = ('name',)
        verbose_name = 'Бот'
        verbose_name_plural = 'Боты'

    def __str__(self):
        return self.name


class Photo(models.Model):
    """Model of photos of examples of the bot's work."""
    photo_examples = models.ImageField(
        'Фото(образцы)',
        upload_to='uploads/examples/%Y/%m/%d/',
    )
    bot = models.ForeignKey(
        Bot,
        on_delete=models.CASCADE,
        verbose_name='Бот',
        related_name='photo_examples'
    )

    class Meta:
        ordering = ('bot',)
        verbose_name = 'Фото(образцы)'
        verbose_name_plural = 'Фото(образцы)'

    def __str__(self):
        return f' Фото бота {self.bot}'

serializers.py

class PhotoSerializer(serializers.ModelSerializer):
    """Serializer of photo bot examples"""
    photo_examples = Base64ImageField()

    class Meta:
        model = Photo
        fields = '__all__'


class CategoryNameSerializer(serializers.PrimaryKeyRelatedField):
    def to_representation(self, value):
        return value.name


class AbstractBotSerializer(serializers.ModelSerializer):
    """
    An abstract class that defines serialization and
deserialization behavior for bot-related data.
    """
    photo_examples = PhotoSerializer(many=True)
    author = serializers.StringRelatedField(read_only=True)
    discount_author = serializers.SerializerMethodField()
    discount_category = serializers.SerializerMethodField()
    amount_discounts_sum = serializers.SerializerMethodField()
    final_price = serializers.SerializerMethodField()
    categories = CategoryNameSerializer(
        required=False,
        queryset=Category.objects.all(),
        many=True,
    )

    class Meta:
        abstract = True
        fields = '__all__'

views.py

class BotViewSet(ModelViewSet):
    """The viewset for the bot.
    With the possibility of pagination, search by name
    and description, filtering by category"""
    queryset = Bot.objects.all()
    serializer_class = BotSerializer
    pagination_class = LimitPageNumberPagination
    filter_backends = (filters.SearchFilter, DjangoFilterBackend, )
    search_fields = ('name', 'description')
    permission_classes = (IsAuthorOrReadOnly, IsAuthor,)
    filterset_fields = ('categories', )

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return BotReviewRatingSerializer
        return self.serializer_class

    def perform_create(self, serializer):
        discount_author = self.request.data.get("discount_author", 0)

        bot_instance = serializer.save(author=self.request.user)

        bot_discount, created = BotDiscount.objects.get_or_create(
            bot=bot_instance, defaults={"discount": discount_author}
        )

        if not created:
            bot_discount.discount = discount_author
            bot_discount.save()

我想以大约这种格式传输数据,但是如果有一种方法可以更轻松地实现多个等碱基,那么您可以使用另一种方法来传输一些等碱基。

POST 请求

{
    "name": "My Bot New",
    "description": "This is my bot",
    "main_photo": "data:image/jpeg;base64,/9j/4A....A/9k=",
    "price": 500,
    "discount_author": 35,
    "categories": [6, 4],
    "photo_examples": [
        {
        "photo_examples": "data:image/jpeg;base64,/9j/4A....A/9k="
        },
        {
        "photo_examples": "data:image/jpeg;base64,/9j/4A....A/9k="
        }
    ]
}

现在我收到一个错误:

{
    "photo_examples": [
        {
            "bot": [
                "Required field"
            ]
        },
        {
            "bot": [
                "Required field."
            ]
        }
    ]
}
django-rest-framework base64 django-serializer

评论


答:

0赞 Maxim K 11/7/2023 #1

添加到perform_create views.py:

    # extracts the photo data from the request data
    photos_data = self.request.data.get('photo_examples', None)
    if photos_data:
        # walk through each photo
        for photo_data in photos_data:
            photo_examples_data = photo_data.get('photo_examples', None)
            if photo_examples_data:
                # creates a new instance of a photo using a bot instance
                photo = Photo.objects.create(bot=bot_instance)
                #  saves photo_examples data in an instance Photo
                photo.photo_examples.save(
                    f"{photo.pk}.jpg",
                    ContentFile(base64.b64decode(
                        photo_examples_data.split(',')[1])),
                    save=True
                )

В serializers.py 重新定义了该领域photo_examples

photo_examples = PhotoSerializer(many=True, read_only=True)