如何在Django POST请求中添加多张Base64编码图片
问题描述
我需要发起POST请求创建Bot实例,同时传递多张Base64编码的photo_examples图片。默认的Base64ImageField仅支持单图上传,我已搭建好多图上传的结构,但提交指定格式的请求时,出现photo_examples的bot字段必填错误,相关代码及请求、错误信息如下:
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." ] } ] }
解决方法
1. 修改PhotoSerializer,标记bot字段为只读
由于Bot实例还未创建时无法提供有效的bot ID,需要让序列化器跳过对bot字段的前端验证,改为后端自动关联:
class PhotoSerializer(serializers.ModelSerializer): """Serializer of photo bot examples""" photo_examples = Base64ImageField() bot = serializers.PrimaryKeyRelatedField(read_only=True) # 添加此行,设为只读 class Meta: model = Photo fields = '__all__'
2. 在BotSerializer中重写create方法,处理嵌套图片数据
AbstractBotSerializer是抽象类,实际使用的BotSerializer需要继承它并手动处理嵌套的photo_examples数据,在Bot创建完成后关联图片:
class BotSerializer(AbstractBotSerializer): class Meta(AbstractBotSerializer.Meta): model = Bot def create(self, validated_data): # 从验证后的数据中取出图片列表,先移除避免干扰Bot创建 photo_examples_data = validated_data.pop('photo_examples', []) # 调用父类方法创建Bot实例 bot = super().create(validated_data) # 批量创建Photo实例并关联当前Bot for photo_data in photo_examples_data: Photo.objects.create(bot=bot, **photo_data) return bot
3. 保留原有视图逻辑
perform_create方法无需修改,它会在Bot实例创建完成后自动处理折扣相关逻辑,不影响图片关联流程。
经过以上修改,前端提交请求时无需传递bot字段,后端会在创建Bot实例后自动将所有示例图片与该Bot关联,解决必填字段错误的同时实现多图上传功能。
内容的提问来源于stack exchange,提问作者Maxim K
相关产品推荐
相关产品推荐

