Я хочу сохранить посткрытие и соответствующий миниатюру посткрытия в меньшем разрешении. В конечном итоге пользователи также могут изменить посткрытие. Для достижения sh правильной обработки файлов я работаю с model.signals. кажется, что это работает довольно хорошо, пока я не попытаюсь изменить посткрытие моего объекта Post.
Когда я пытаюсь сохранить объект Post с измененным посткрытием, я получаю следующую ошибку:
ValueError: The 'postcover' attribute has no file associated with it.
Первоначальное создание и удаление объекта Post работает, как и ожидалось.
models.py
class Post(models.Model):
...
postcover = models.ImageField(
verbose_name="Post Cover",
blank=True,
null=True,
)
postcover_tn = models.ImageField(
verbose_name="Post Cover Thumbnail",
blank=True,
null=True,
)
...
def save(self, *args, **kwargs):
super(Post, self).save(*args, **kwargs)
if self.postcover:
if os.path.exists(self.postcover.path):
image = Image.open(self.postcover)
outputIoStream = BytesIO()
baseheight = 600
hpercent = baseheight / image.size[1]
wsize = int(image.size[0] * hpercent)
imageTemproaryResized = image.resize((wsize, baseheight))
imageTemproaryResized.save(outputIoStream, format='PNG')
outputIoStream.seek(0)
self.postcover = InMemoryUploadedFile(outputIoStream, 'ImageField',
"%s.png" % self.postcover.name.split('.')[0], 'image/png',
sys.getsizeof(outputIoStream), None)
image = Image.open(self.postcover)
outputIoStream = BytesIO()
baseheight = 100
hpercent = baseheight / image.size[1]
wsize = int(image.size[0] * hpercent)
imageTemproaryResized = image.resize((wsize, baseheight))
imageTemproaryResized.save(outputIoStream, format='PNG')
outputIoStream.seek(0)
self.postcover_tn = InMemoryUploadedFile(outputIoStream, 'ImageField',
"%s.png" % self.postcover.name.split('.')[0], 'image/png',
sys.getsizeof(outputIoStream), None)
elif self.postcover_tn:
self.postcover_tn.delete()
super(Post, self).save(*args, **kwargs)
signal.py
@receiver(models.signals.post_save, sender=Post)
def post_auto_delete_files_on_change(sender, instance, **kwargs):
"""
Deletes old file from filesystem
when corresponding object is updated
with new file.
"""
if not instance.pk:
return False
try:
old_postcover = sender.objects.get(pk=instance.pk).postcover
old_postcover_tn = sender.objects.get(pk=instance.pk).postcover_tn
except sender.DoesNotExist:
return False
if not old_postcover:
return False
new_postcover = instance.postcover
if not old_postcover == new_postcover:
if os.path.isfile(old_postcover.path):
os.remove(old_postcover.path)
os.remove(old_postcover_tn.path)
У меня также есть опция удаления в postcover мой forms.py, который может повлиять на этот процесс:
if self.instance.postcover:
self.fields['remove_cover'].disabled = False
self.fields['postcover'].label = mark_safe('Overwrite Cover:')
self.fields['remove_cover'].label = mark_safe('Remove Cover:')
else:
self.fields['postcover'].label = mark_safe('Cover:')
del self.fields['remove_cover']
def save(self, commit=True):
instance = super(PostForm, self).save(commit=False)
if self.cleaned_data.get('remove_cover'):
try:
os.unlink(instance.postcover.path)
except OSError:
pass
instance.postcover = None
if self.cleaned_data.get('remove_attachment'):
try:
os.unlink(instance.postattachment.path)
except OSError:
pass
instance.postattachment = None
if commit:
instance.save()
return instance