Django Value Error "seek of closed file" при использовании PIL для изменения размера изображения при обновлении записи

У меня следующая модель:

class Players(models.Model):
    team = models.ForeignKey(Teams, verbose_name=_('Team'), on_delete=models.CASCADE)
    player_name = models.CharField(_('Player Name'),max_length=200)
    player_description = models.TextField(_('Player Description'))
    player_image = models.ImageField(_('Profile Pic'),upload_to='upload/player_image', null=True, blank=True)
    player_social = models.CharField(_('Social Media Tag'),max_length=200)

    class Meta:
        verbose_name = _("Players")
        verbose_name_plural = _("Players")

    def __str__(self):
        return self.team.team_name + ' - ' + self.player_name
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if self.player_image:
            image_resize(self.player_image, 250)

Последняя функция вызовет другую для изменения размера изображения, взяв файл и ожидаемую максимальную ширину:

# Use PIL to resize images; set target width on each
def image_resize(image, tgt_width):
        img = PIL.Image.open(image)
        img.load()
        width, height = img.size
        target_width = tgt_width
        h_coefficient = width/tgt_width
        target_height = height/h_coefficient
        img = img.resize((int(target_width), int(target_height)), PIL.Image.ANTIALIAS)
        img.save(image.path, quality=100)
        img.close()
        image.close()

Мое мнение по поводу обновления следующее:

@method_decorator(superuser_required, name='dispatch')
class PlayerUpdateView(UpdateView):
    model = Players
    template_name = 'scoreboard/players/player_update.html'
    form_class = PlayersForm
    context_object_name: str = 'player'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        team_id = Players.objects.get(pk=self.kwargs['pk']).team.id
        context["team"] = Teams.objects.get(pk=team_id)
        return context
    
    def form_valid(self, form):
        form.save()
        return super().form_valid(form)

    def get_success_url(self):
        team_id = Players.objects.get(pk=self.kwargs['pk']).team.id
        return reverse_lazy('team_detail', kwargs={'pk': team_id})

Не имеет значения, предоставляю ли я новый файл изображения или нет, я получаю ту же ошибку "seek of closed file":

  File "D:\00_www\hts-score\overlay\scoreboard\models.py", line 62, in save
    image_resize(self.player_image, 250)
  File "D:\00_www\hts-score\overlay\scoreboard\models.py", line 15, in image_resize
    img = PIL.Image.open(image)
  File "D:\00_www\hts-score\venv\lib\site-packages\PIL\Image.py", line 3096, in open
    fp.seek(0)
ValueError: seek of closed file

Как я могу заставить изображение обрабатываться в любом случае? Чего мне не хватает?

Я попробовал добавить метод if, чтобы в случае отсутствия файла не запускать функцию изменения размера. Я ожидал, что функция проверит наличие файла изображения, а затем обработает его. Добавление img.load() не помогает

Итак, после нескольких попыток я нашел этот ответ. Я не очень уверен, почему это работает, но похоже, что метод with правильно открывает и закрывает файл. Нашел это на PIL Documentation. Функция image_resize() будет выглядеть следующим образом:

def image_resize(image, tgt_width):
    with Image.open(image) as img:
        width, height = img.size
        ratio = width / height
        tgt_height = int(tgt_width / ratio)
        img = img.resize((tgt_width, tgt_height), Image.ANTIALIAS)
        img.save(image.path)

С условием if в методе сохранения, это работает каждый раз.

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