Reputation: 1121
I had some research on web for this problem on DRF. When one image is in post DRF works great. But when 3 or 5 images are in one post there is problem that Django save only first image from POST query and others are not saved in database. The question is how to properly handle multiply images upload in one post.
Django version
Rest framework version
Python version
Here is my code what I was trying to do:
class UserModel(AbstractEmailUser):
first_name = models.CharField(max_length=30, db_index=True)
last_name = models.CharField(max_length=50, db_index=True)
details = JSONField(null=True, blank=True, db_index=True)
avatar = models.ImageField(blank=True, null=True, upload_to='avatar')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.email)
class UserImages(models.Model):
image = models.ImageField(upload_to='images', db_index=True)
user = models.ForeignKey('UserModel',related_name='user')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.user)
Here in models I have related field from User to UserImages. For purpose on POST query from postman I manual add ID from user to handle FK.
class SerializerUserImages(serializers.ModelSerializer):
class Meta:
model = UserImages
def create(self, validated_data):
imgs = UserImages.objects.create(**validated_data)
return imgs
Maybe here I must do some for loop to accomplish save method for multiply images.
class UploadImages(APIView):
authentication_classes = (JSONWebTokenAuthentication,)
@parser_classes((FormParser, MultiPartParser, FileUploadParser))
def post(self, request, format=None):
serializer = SerializerUserImages(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data={"msg": serializer.data}, status=status.HTTP_200_OK)
else:
return Response(data={"msg": serializer.errors}, status=status.HTTP_406_NOT_ACCEPTABLE)
All parsers are included for handling this post query.
This is output from request.data = <QueryDict: {'image': [<InMemoryUploadedFile: top_20_cro.png (image/png)>, <InMemoryUploadedFile: images.jpg (image/jpeg)>], 'user': ['2', '2']}>
This is copy of request POST from POSTMAN:
POST /api/images/ HTTP/1.1
Host: 127.0.0.1:8000
Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmlnX2lhdCI6MTQ3MjIwMTcwMSwiZXhwIjoxNDcyMjMxNzAxLCJ1c2VyX2lkIjoyLCJlbWFpbCI6Im1hcmluLmJyZWthbG9AZ21haWwuY29tIiwidXNlcm5hbWUiOiJtYXJpbi5icmVrYWxvQGdtYWlsLmNvbSJ9.Fi3kmXJ44E_qhHHioniQ-cqri-u2ELU-XmpE_1oJ4Fk
Cache-Control: no-cache
Postman-Token: 1e53ac06-ed37-ff6e-2dc5-117976b86a5e
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="image"; filename=""
Content-Type:
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="user"
2
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="filename"
image
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="user"
2
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="filename"
image
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="image"; filename=""
Content-Type:
------WebKitFormBoundary7MA4YWxkTrZu0gW--
How can this be handled without some great magic, is there some easy logic that I missed up.
Upvotes: 1
Views: 1908
Reputation: 1121
Ok here is my some logic about this problem, so I hope someone will use this code (hack) for this purpose:
class SerializerTest(serializers.Serializer):
image = serializers.ListField(child=serializers.ImageField(required=True))
def create(self, validated_data):
for attr, value in validated_data.items():
if attr == 'image':
for x in value:
c = UserImages.objects.create(image=x, user_id=UserModel.objects.get(id=self.context['request'].user.id).id)
c.save()
return validated_data
I have updated my serialzer for just one field img. And use for loop to extract images from POST. As you can see i call query to store images to database on FK user. This work's very good.
class UploadImages(APIView):
authentication_classes = (JSONWebTokenAuthentication,)
@parser_classes((FormParser, MultiPartParser, FileUploadParser))
def post(self, request, format=None):
serializer = SerializerTest(data=request.data, context={'request':request})
if serializer.is_valid():
serializer.save()
if len(serializer.data['image']) > 0:
que = UserImages.objects.filter(user=request.user.id)
ser = SerializerUserImages(que, many=True)
return Response(data={"msg": ser.data}, status=status.HTTP_200_OK)
else:
return Response(data={"msg": 'Provide images!'}, status=status.HTTP_406_NOT_ACCEPTABLE)
else:
return Response(data={"msg": serializer.errors}, status=status.HTTP_406_NOT_ACCEPTABLE)
Upvotes: 1
Reputation: 776
Simply add
many=True
with the serializer initializer. For eg.:
serializer = SerializerUserImages(data=request.data, many=True)
This should do the trick.
Also have a look at ListSerializers
Upvotes: 0
Reputation: 2339
Try setting filenames for your images, I mean replace filename=""
with something like filename="image-1"
, filename="image-2"
, etc. Files should have different filenames or they override each other.
Upvotes: 0