validators for bulk image upload

I have a feature that allows users to upload multiple images. I want to setup a validator to only allow images that are under 3MB.

def validate_image_bulk(images):

    file_size = images.file.size
    if file_size > settings.MAX_UPLOAD_SIZE:
        raise ValidationError(f'Cover Image {images} is too large 3mb max')

How can I get a list of the images being uploaded and validate them at the same time. In a view I could do something like request.FILES.getlist('images') is there something similar like this?


Solution 1:

Things to understand

  1. images in validate_image_bulk is a single file (that's what models.ImageField handles and that's why you do images.file.size same as image.file.size in validate_image).
  2. validate_image_bulk is always called with the same file (specifically, the last file) from PostImagesForm(request.POST, request.FILES).
  3. for x in images in validate_images_bulk loops over the bytes, not multiple images.

Solution

Do PostImagesForm(request.POST, {'images': image}) instead:

post_images_forms = []
for image in request.FILES.getlist('images'):
    post_images_form = PostImagesForm(request.POST, {'images': image})
    if not post_images_form.is_valid():
        break
    post_images_forms.append(post_images_form)
else:  # if len(post_images_forms) == len(request.FILES.getlist('images')):
    for post_images_form in post_images_forms:
        instance = post_images_form.save(commit=False)
        instance.post_id = PostFormID.id
        instance.save()

Recommendations for sanity

  1. Rename images to image.
  2. Discard validate_images_bulk since it's functionally same as validate_image.
class PostImages(models.Model):
    # images = models.ImageField(validators=[validate_image_bulk])  # Change this
    image = models.ImageField(validators=[validate_image])          # to this

Solution 2:

crate an validator.py inside your app:

validator.py

from django.core.exceptions import ValidationError


def validate_file_size(value):
    filesize = value.size
    
    if filesize > 3145728:  #3 * 1024 * 1024
       raise ValidationError('The maximum file size that can be uploaded is 3MB')
    else:
      return value

your models.py

from .validator import *
from django.core.validators import FileExtensionValidator #if you also want to use file type Validator

class mymodel(models.Model)
      image = models.ImageField(upload_to='blog/images/',validators=[validate_file_size,FileExtensionValidator( ['png','jpg'] )],blank=True,null=True) #only accept 'png' and 'jpg' image.  

You can check django documentation for FileExtensionValidator