Python / Django загрузить изображение с URL, изменить и сохранить в ImageField - PullRequest
10 голосов
/ 10 августа 2010

Я искал способ загрузить изображение с URL-адреса, предварительно настроить некоторые манипуляции с изображениями (изменить его размер), а затем сохранить его в django ImageField.Используя два замечательных поста (ссылка ниже), я смог загрузить и сохранить изображение в ImageField.Тем не менее, у меня возникли некоторые проблемы при работе с файлом, как только он у меня есть.

В частности, метод save () поля модели требует объект File () в качестве второго параметра.Таким образом, мои данные должны в конечном итоге быть объектом File ().Сообщения блога, ссылки на которые приведены ниже, показывают, как использовать urllib2 для сохранения URL-адреса изображения в объекте File ().Это здорово, однако я также хочу манипулировать изображением, используя PIL в качестве объекта Image ().(или объект ImageFile).

Мой предпочтительный подход заключается в том, чтобы затем загрузить URL-адрес изображения непосредственно в объект Image (), предварительно изменить размер и преобразовать его в объект File (), а затем сохранить его в модели.Однако мои попытки конвертировать Image () в File () не увенчались успехом.Если это вообще возможно, я хочу ограничить количество раз, когда я записываю на диск, поэтому я хотел бы выполнить это преобразование объекта в памяти или использовать объект NamedTeilitaryFile (delete = True), чтобы мне не приходилось беспокоиться одополнительные файлы лежали вокруг.(Конечно, я хочу, чтобы файл был записан на диск после его сохранения с помощью модели).

import urllib2
from PIL import Image, ImageFile    
from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

inStream = urllib2.urlopen('http://www.google.com/intl/en_ALL/images/srpr/logo1w.png')

parser = ImageFile.Parser()
while True:
    s = inStream.read(1024)
    if not s:
        break
    parser.feed(s)

inImage = parser.close()
# convert to RGB to avoid error with png and tiffs
if inImage.mode != "RGB":
    inImage = inImage.convert("RGB")

# resize could occur here

# START OF CODE THAT DOES NOT SEEM TO WORK
# I need to somehow convert an image .....

img_temp = NamedTemporaryFile(delete=True)
img_temp.write(inImage.tostring())
img_temp.flush()

file_object = File(img_temp)

# .... into a file that the Django object will accept. 
# END OF CODE THAT DOES NOT SEEM TO WORK

my_model_instance.image.save(
         'some_filename',
         file_object,  # this must be a File() object
         save=True,
         )

При таком подходе файл выглядит поврежденным всякий раз, когда я рассматриваю его как изображение.Есть ли у кого-нибудь подход, который берет файл файла из URL, позволяет ему манипулировать им как изображением, а затем сохранять его в Django ImageField?

Любая помощь очень ценится.

Программное сохранение изображения в Django ImageField

Django: добавить изображение в ImageField из URL-адреса изображения

Обновление 08/11/ 2010: я закончил тем, что перешел на StringIO, однако, я был stringIO, который выдавал необычное исключение, когда пытался сохранить его в Django ImageField.В частности, трассировка стека показала ошибку имени:

"AttribueError exception "StringIO instance has no attribute 'name'"

После копания в источнике Django, похоже, эта ошибка была вызвана, когда при сохранении модели был получен доступ к атрибуту размера StringIO «Файл».(Хотя вышеприведенная ошибка указывает на проблему с именем, основной причиной этой ошибки, по-видимому, является отсутствие свойства размера на изображении StringIO).Как только я присвоил значение атрибуту size файла изображения, все заработало нормально.

1 Ответ

4 голосов
/ 10 августа 2010

В попытке убить 2 зайцев одним выстрелом. Почему бы не использовать объект (c) StringIO вместо NamedTeoraryFile? Вам больше не придется хранить его на диске, и я точно знаю, что что-то подобное работает (я сам использую подобный код).

from cStringIO import StringIO
img_temp = StringIO()
inImage.save(img_temp, 'PNG')
img_temp.seek(0)

file_object = File(img_temp, filename)
...