I want to make a POST request to create a bot, while I want to transfer several photo_examples images that are encoded in base64. By default, when using Base64ImageField, only one image can be added, and I need to add several. I tried to look at other projects on the Internet, but I didn't find a solution how to implement it.
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()
I want to transmit data in approximately this format, but if there is a way that will make it easier to implement several isobases, then you can use another way to transfer a few isobases.
POST request
{
"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="
}
]
}
Now I'm getting an error:
{
"photo_examples": [
{
"bot": [
"Required field"
]
},
{
"bot": [
"Required field."
]
}
]
}
Added to views.py in perform_create:
# 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 redefined the field photo_examples
photo_examples = PhotoSerializer(many=True, read_only=True)