Преоразмеряването на качените изображения не работи правилно 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()

Методът за преоразмеряване трябва да вземе съществуващия файл от полето 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
Всъщност, ако type(img) е File, тогава можете да пропуснете реда img.save() и просто да подадете img като втори аргумент на self.resized_image.save() - person iri; 11.10.2020
comment
Благодаря много, един въпрос, към img.save('/tmp/some/temporary/path.png') Трябва да сложа моя upload_path или какво? Можете ли да коментирате последните 2 реда - person messageman; 11.10.2020
comment
Съжалявам, копирах вашия код, без наистина да го проверя, редактирах отговора си. Този път не се записва във временен файл, а във файл в паметта, преди да се запише в полето resized_image. - person iri; 12.10.2020
comment
Благодаря много, работи. Последно q, как да направя така, че да мога да променя не само ширината и височината, но и поотделно? - 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