Пользовательская модель сохранения Django создает дубликаты файлов
Я пытаюсь заставить загружаемые изображения сохраняться как миниатюры, что работает. Проблема в том, что при обновлении пользовательский метод сохраняет миниатюру снова в другой директории. Поэтому я изменил функцию сохранения таким образом.
models.py
class Photo(models.Model):
title = models.CharField(max_length=64)
description = models.CharField(max_length=255)
created = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='photos/%Y%m')
thumbnail = models.ImageField(blank=True, upload_to='thumbnails/%Y%m')
submitter = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
year = models.ForeignKey(Year, blank=True, on_delete=models.CASCADE)
people = TaggableManager(through=TaggedPeople, verbose_name='People')
tags = TaggableManager(through=TaggedGeneric, verbose_name='Tags')
def save(self, *args, **kwargs):
try:
this = Photo.objects.get(id=self.id)
if this.thumbnail != self.thumbnail:
this.thumbnail.delete(save=False)
except:
if self.thumbnail:
img = Image.open(BytesIO(self.thumbnail.read()))
if hasattr(img, '_getexif'):
exif = img._getexif()
if exif:
for tag, label in ExifTags.TAGS.items():
if label == 'Orientation':
orientation = tag
break
if orientation in exif:
if exif[orientation] == 3:
img = img.rotate(180, expand=True)
elif exif[orientation] == 6:
img = img.rotate(270, expand=True)
elif exif[orientation] == 8:
img = img.rotate(90, expand=True)
img.thumbnail((360,360), Image.ANTIALIAS)
output = BytesIO()
img.save(output, format='JPEG', quality=95)
output.seek(0)
self.thumbnail = File(output, self.thumbnail.name)
return super().save(*args, **kwargs)
def __str__(self):
return self.title
и мои взгляды
class PhotoCreateView(LoginRequiredMixin, CreateView):
model = Photo
fields = ['image', 'title', 'description', 'year', 'people', 'tags']
template_name = 'photoapp/create.html'
success_url = '/photo/?page=1'
extra_context = {'tags':GenericTag.objects.all().order_by('name'),'people':PeopleTag.objects.all().order_by('name'),}
def form_valid(self, form):
form.instance.thumbnail = self.request.FILES['image']
form.instance.submitter = self.request.user
return super().form_valid(form)
class PhotoUpdateView(LoginRequiredMixin, UpdateView):
template_name = 'photoapp/update.html'
model = Photo
fields = ['title', 'description', 'year', 'people', 'tags']
success_url = '/photo/?page=1'
Теперь CreateView работает нормально, и я остановил дублирование файлов миниатюр, но UpdateView не работает. Как я могу это исправить?
Я разобрался с этим. Мне просто нужно было добавить сохранение в секцию try.
def save(self, *args, **kwargs):
try:
this = Photo.objects.get(id=self.id)
if this.thumbnail != self.thumbnail:
this.thumbnail.delete(save=False)
return super().save(*args, **kwargs)
except:
if self.thumbnail:
img = Image.open(BytesIO(self.thumbnail.read()))
if hasattr(img, '_getexif'):
exif = img._getexif()
if exif:
for tag, label in ExifTags.TAGS.items():
if label == 'Orientation':
orientation = tag
break
if orientation in exif:
if exif[orientation] == 3:
img = img.rotate(180, expand=True)
elif exif[orientation] == 6:
img = img.rotate(270, expand=True)
elif exif[orientation] == 8:
img = img.rotate(90, expand=True)
img.thumbnail((360,360), Image.ANTIALIAS)
output = BytesIO()
img.save(output, format='JPEG', quality=95)
output.seek(0)
self.thumbnail = File(output, self.thumbnail.name)
return super().save(*args, **kwargs)
У меня была похожая проблема в Django-Wagtail, где сохранение image.save() программно дублировало в файловой системе импортированное изображение. Чтобы обойти это, я использовал Python Glob для получения пути и OS для удаления исходного изображения после загрузки функции сохранения. Это достаточно хорошо работает для Wagtail, но я хотел описать проблему для других - поскольку в Интернете об этом мало что известно. Это расстраивает, если вы не будете осторожны, использование дискового пространства удвоится из-за этой функции! Мне не нравится, что он переименовывает файлы/перемещает их, но это то, что есть.
from django.core.management.base import BaseCommand, CommandError
from wagtail.images.models import Image
from django.core.files.images import ImageFile
import os
from os import path
import glob
#import sqlite3
class Command(BaseCommand):
help = "just a thing to "
def handle(self, *args, **options):
target_path = "/home/inmyth/inmyth/media/images/"
my_images = []
if os.path.exists(target_path):
my_images = glob.glob(target_path + "*.png")
for mj_imgs in my_images:
print(mj_imgs)
image_file = ImageFile(open(mj_imgs, 'rb'), name=mj_imgs[:-4])
img_label = mj_imgs.rfind("/") + 1
image = Image(title=mj_imgs[img_label:-4], file=image_file)
image.save()
os.remove(mj_imgs)
pass