Валидаторы для массовой загрузки изображений

Я установил валидатор для поля загрузки изображения, чтобы проверить, не является ли изображение слишком большим, он работает, как ожидалось.

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

image = models.ImageField(default='default.jpg', storage=PublicMediaStorage(), upload_to=path_and_rename, validators=[validate_image])

Теперь я хочу сделать то же самое для поля массовой загрузки изображений, которое у меня есть.

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

images = models.ImageField(upload_to=path_and_rename_bulk, validators=[validate_image])

Если вы загружаете несколько изображений и одно из них превышает максимальный порог загрузки, то ни одно из них не загружается и не выдает ошибку валидации, но форма все равно отправляется. Если вы загружаете одно изображение слишком большого размера, происходит то же самое

Как я могу вызвать ошибку валидации и не допустить отправки формы, как это происходит для поля с одним изображением

view: (объемная модель - PostImagesForm)

postForm = PostForm()
if request.method == 'POST':
    postForm = PostForm(request.POST, request.FILES)

    if len(request.FILES.getlist('images')) > 30:
        raise Exception("Max of 30 images allowed")
    else:        
        if postForm.is_valid():
            PostFormID = postForm.save(commit=False)
            PostFormID.author = request.user
            PostFormID.save()                       
            if len(request.FILES.getlist('images')) == 0:
                return redirect('post-detail', PostFormID.pk)
            else:
                for f in request.FILES.getlist('images'):          
                    test = PostImagesForm(request.POST, request.FILES)
                    if test.is_valid():
                        instance = test.save(commit=False)
                        instance.post_id = PostFormID.id
                        instance.images = f
                        instance.save()   
            return redirect('post-detail', PostFormID.pk)

Что нужно понять

  1. images в validate_image_bulk - это один файл (это то, что обрабатывает models.ImageField и поэтому вы делаете images.file.size таким же, как image.file.size в validate_image).
  2. validate_image_bulk всегда вызывается с тем же файлом (в частности, последним файлом) из PostImagesForm(request.POST, request.FILES).
  3. for x in images в validate_images_bulk перебирает байты, а не несколько изображений.

Решение

Вместо этого сделайте PostImagesForm(request.POST, {'images': image}):

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()

Рекомендации для здравомыслия

  1. Переименовать images в image.
  2. Избавьтесь от validate_images_bulk, поскольку функционально это то же самое, что и validate_image.
class PostImages(models.Model):
    # images = models.ImageField(validators=[validate_image_bulk])  # Change this
    image = models.ImageField(validators=[validate_image])          # to this

создайте validator.py внутри вашего приложения:

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

ваш 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.  

Вы можете проверить документацию django для FileExtensionValidator

Вернуться на верх