-
Тренируюсь с загрузкой изображений. В форме присутствует лишь одно поле - avatar класса ImageField. Хочу до момента сохранения загруженного изображения изменить его размер. Пытаюсь делать это в функции clean_avatar:
Все бы хорошо, но вылезает ошибка: 'InMemoryUploadedFile' object has no attribute '_mode'.def clean_avatar(self):
image = self.cleaned_data['avatar']
from PIL import Image
from StringIO import StringIO
if hasattr(image, 'temporary_file_path'):
f = image.temporary_file_path()
else:
if hasattr(image, 'read'):
f = StringIO(image.read())
else:
f = StringIO(image['content'])
img = Image.open(f)
img.thumbnail((48, 48), Image.ANTIALIAS)
img.save(image, 'JPEG')
return image
Полазил по исходникам и обнаружил, что атрибут mode не присваивается в момент создания объекта InMemoryUploadedFile. Таким образом простейший image.write не работает для объектов данного класса. Что делать в таком случае? Есть варианты обхода?
Большая просьба не предлагать перенести процесс изменения размера изображения в метод save модели. Представьте, что нагрузка на машину настолько высока, что нельзя позволить себе сохранение файла, затем его чтение и повторное сохранение уже измененного изображения, и нужно делать все за один подход. -
Что делать в таком случае?Цчиться использовать поиск: http://softwaremaniacs.org/forum/django/3133/
-
Перед тем как спросить я поискал. Я не из тех, кто вначале загадит форум тьмой вопросов, а в следующую секунду найдет ответ в первом же непрочтенном топике.
Во-вторых, вы мне дали ссылку на преобразование файла, который уже находится в storage, а я просил указать вариант обработки изображения еще не сохраненного в файл.
Самостоятельно пришел к следующему варианту.
Спасибо за помощь.class AvatarUploadForm(forms.ModelForm):
"""
Форма загрузки аватара.
Преобразует загруженное изображение к размеру AVATAR_SIZE пикселей.
"""
class Meta:
model = UserProfile
fields = ('avatar',)
def clean_avatar(self):
image = self.cleaned_data['avatar']
# Ограничиваем максимальный размер загружаемого изображения величиной
# максимального загружаемого в память файла
if image.size > settings.FILE_UPLOAD_MAX_MEMORY_SIZE:
raise forms.ValidationError(u'Размер изображения превышает %i Мб.' % \
(settings.FILE_UPLOAD_MAX_MEMORY_SIZE / (1024*1024)))
from django.core.files.uploadedfile import InMemoryUploadedFile
from PIL import Image
from StringIO import StringIO
f = StringIO(image.read())
thumb = StringIO()
img = Image.open(f)
if img.mode != "RGB":
img = img.convert("RGB")
# Метод thumb не используется, т.к. он не увеличивает размер изображения,
# если оно меньше требуемого
img = img.crop((0, 0, min(img.size), min(img.size)))
img = img.resize(settings.AVATAR_SIZE, Image.ANTIALIAS)
img.save(thumb, 'JPEG')
return InMemoryUploadedFile(thumb, image.field_name, image.name, image.content_type, thumb.len, image.charset)
def save(self):
"""
Удаление старого аватара перед сохранением нового с тем же именем.
"""
img = self.instance.avatar
if img.name != img.field.default:
img.storage.delete(img.name)
super(AvatarUploadForm, self).save() -
Евгений, в целом хорошо, но есть одно замечание:
методы clean_XXX в моделях используются как правило только для проверки корректности данных. Для обработки данных перед сохранением (или после него) лучше использовать все-таки метод save, для этого он и предназначен.
С одной стороны работать все равно будет одинаково, но с другой стороны если Ваш код будет в последствии дорабатываться другим программистом он может и не уловить такие тонкости. -
А насколько корректно будет перенести код ресайза изображения в метод save формы, а не модели? И, кстати, на момент вызова form.save загруженный файл находится где: в памяти или уже на диске?
-
Можно еще глянуть на готовые варианты:
http://hg.driscolldev.com/django-imagekit/wiki/Home
http://code.google.com/p/django-photologue/ -
Ну и http://code.google.com/p/sorl-thumbnail/ в коллекцию, мне он показался самым удобным.
Вообще непонятно откуда берется привычка всё писать самому? Это ж типовая задача, для нее 99.99% найдутся готовые решения. -
Тут штука в том, что всеразличные ThumbnailField'ы — идеальная задачка для того, кто хочет разобраться, что там как в моделях и формах устроено. Из серии "Everyone has to write his own ThumbnailField and never use it" :-)
-
А ну да, это из серии, что каждый админ должен написать свой биллинг :)
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.


