Валидаторы для массовой загрузки изображений
Я установил валидатор для поля загрузки изображения, чтобы проверить, не является ли изображение слишком большим, он работает, как ожидалось.
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)
Что нужно понять
imagesвvalidate_image_bulk- это один файл (это то, что обрабатываетmodels.ImageFieldи поэтому вы делаетеimages.file.sizeтаким же, какimage.file.sizeвvalidate_image).validate_image_bulkвсегда вызывается с тем же файлом (в частности, последним файлом) изPostImagesForm(request.POST, request.FILES).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()
Рекомендации для здравомыслия
- Переименовать
imagesвimage. - Избавьтесь от
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