Изменение размера загруженных изображений работает неправильно Django

у меня есть модель

upload_path = 'images'
upload_path_to_resize = 'resized'


class Images(models.Model):
    image = models.ImageField(upload_to=upload_path, blank=True, null=True)
    image_url = models.URLField(blank=True, null=True)
    image_resized = models.ImageField(upload_to=upload_path_to_resize,blank=True)
    width = models.PositiveIntegerField(null=True)
    heigth = models.PositiveIntegerField(null=True)

def clean(self):
    if (self.image == None and self.image_url == None ) or (self.image != None and self.image_url != None ):
        raise ValidationError('Empty or both blanked')

def get_absolute_url(self):
    return reverse('image_edit', args=[str(self.id)])

def save(self):
    if self.image_url and not self.image:
        name = str(self.image_url).split('/')[-1]
        img = NamedTemporaryFile(delete=True)
        img.write(urlopen(self.image_url).read())
        img.flush()
        self.image.save(name, File(img))
        self.image_url = None
    super(Images, self).save()

def resize(self):
    if (self.width != None) or (self.heigth != None):
        img = Image.open(self.image.path)
        output_size = (self.width, self.heigth)
        img.thumbnail(output_size)
        img.save(self.image_resized.path)
        super(Images, self).save()

Метод resize должен взять существующий файл из поля ImageField, изменить размер и загрузить в поле image_resized, но форма FormResize почему-то передает в модель аргументы высоты и ширины, но ничего не происходит

from django.forms import ModelForm
from .models import Images

class ImageForm(ModelForm):
    class Meta:
        model = Images
        fields = ['image', 'image_url']

class ResizedForm(ModelForm):
    class Meta:
        model = Images
        fields = ['width', 'heigth']

Что мне нужно сделать, чтобы изменение размера работало правильно?


person messageman    schedule 11.10.2020    source источник


Ответы (2)


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

Пытаться:

from django.core.files import File
import os.path
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile

def resize(self):
    if self.width and self.heigth:
        img = Image.open(self.image)
        output_size = (self.width, self.heigth)
        img.thumbnail(output_size)
        thumb_name, thumb_extension = os.path.splitext(self.image.name)
        thumb_extension = thumb_extension.lower()
        thumb_filename = thumb_name + '_thumb' + thumb_extension

        if thumb_extension in ['.jpg', '.jpeg']:
            FTYPE = 'JPEG'
        elif thumb_extension == '.gif':
            FTYPE = 'GIF'
        elif thumb_extension == '.png':
            FTYPE = 'PNG'
        else:
            return False    # Unrecognized file type

        # Save thumbnail to in-memory file as StringIO
        temp_thumb = BytesIO()
        img.save(temp_thumb, FTYPE)
        temp_thumb.seek(0)

        self.image_resized.save(thumb_filename, ContentFile(temp_thumb.read()))
        temp_thumb.close()

При сохранении resized_image вам нужно передать имя файла и двоичный объект, который будет сохранен, а не только путь.

Вам не понадобится вызов super().save(), если вы сделаете это, поскольку вы сохраняете поле resized_image внутри функции изменения размера.

Я не тестировал этот код, сделал бы комментарий, но он был слишком длинным.

person iri    schedule 11.10.2020
comment
На самом деле, если тип (img) - это файл, вы можете пропустить строку img.save() и просто передать img в качестве второго аргумента для self.resized_image.save() - person iri; 11.10.2020
comment
Большое спасибо, один вопрос, в img.save('/tmp/some/temporary/path.png') мне нужно указать путь для загрузки или как? Можешь прокомментировать последние 2 строчки - person messageman; 11.10.2020
comment
Извините, я скопировал ваш код, не проверив его, я отредактировал свой ответ. На этот раз он сохраняется не во временный файл, а в файл в памяти перед сохранением в поле resized_image. - person iri; 12.10.2020
comment
Большое спасибо, все работает. Последний вопрос, как сделать так, чтобы я мог менять не только ширину и высоту, но и отдельно? - person messageman; 12.10.2020
comment
Если ответ работает, отметьте его как правильный для будущих читателей. Я интерпретирую ваш вопрос как вопрос о том, как изменить только высоту или только ширину, вы можете получить исходные размеры изображения, используя from django.core.files.images import get_image_dimensions, а затем width, height = get_image_dimensions(self.image.file), а затем реорганизовать свою функцию изменения размера оттуда. - person iri; 12.10.2020
comment
Спасибо. Отметил ваш ответ. - person messageman; 12.10.2020

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

https://github.com/un1t/django-resized

person Mrlucas2809    schedule 11.10.2020
comment
Мне нужно сделать это самостоятельно - person messageman; 11.10.2020
comment
В этом случае попробуйте прочитать код приложения с измененным размером django, это даст вам подсказку;) - person Mrlucas2809; 11.10.2020
comment
Понимаю, но голова уже кипит, не могу адекватно воспринимать информацию, хотелось бы свежего взгляда и советов как поправить код - person messageman; 11.10.2020
comment
Добро пожаловать в StackOverflow! Хотя это может ответить на вопрос, было бы предпочтительнее включить сюда основные части ответа и предоставить ссылку для ссылка. - person Sergey Shubin; 13.10.2020