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

пожалуйста, извините меня за мой уродливый английский; -)

Представьте себе эту очень простую модель:

class Photo(models.Model):
    image = models.ImageField('Label', upload_to='path/')

Я хотел бы создать фотографию с URL-адреса изображения (т.е. не вручную на сайте администратора django).

Я думаю, что мне нужно сделать что-то вроде этого:

from myapp.models import Photo
import urllib

img_url = 'http://www.site.com/image.jpg'
img = urllib.urlopen(img_url)
# Here I need to retrieve the image (as the same way that if I put it in an input from admin site)
photo = Photo.objects.create(image=image)

Надеюсь, что я хорошо объяснил проблему, если не сказал мне.

Спасибо:)

Изменить:

Это может работать, но я не знаю, как преобразовать content в файл django:

from urlparse import urlparse
import urllib2
from django.core.files import File

photo = Photo()
img_url = 'http://i.ytimg.com/vi/GPpN5YUNDeI/default.jpg'
name = urlparse(img_url).path.split('/')[-1]
content = urllib2.urlopen(img_url).read()

# problem: content must be an instance of File
photo.image.save(name, content, save=True)

Ответ 1

Я только что создал http://www.djangosnippets.org/snippets/1890/ для этой же проблемы. Код похож на ответ pithyless выше, за исключением того, что использует urllib2.urlopen, потому что urllib.urlretrieve по умолчанию не выполняет обработку ошибок, поэтому легко получить содержимое страницы 404/500 вместо того, что вам нужно. Вы можете создать функцию обратного вызова и собственный подкласс URLOpener, но мне было проще просто создать собственный файл temp, например:

from django.core.files import File
from django.core.files.temp import NamedTemporaryFile

img_temp = NamedTemporaryFile(delete=True)
img_temp.write(urllib2.urlopen(url).read())
img_temp.flush()

im.file.save(img_filename, File(img_temp))

Ответ 2


from myapp.models import Photo
import urllib
from urlparse import urlparse
from django.core.files import File

img_url = 'http://www.site.com/image.jpg'

photo = Photo()    # set any other fields, but don't commit to DB (ie. don't save())
name = urlparse(img_url).path.split('/')[-1]
content = urllib.urlretrieve(img_url)

# See also: http://docs.djangoproject.com/en/dev/ref/files/file/
photo.image.save(name, File(open(content[0])), save=True)

Ответ 3

ImageField - это просто строка, путь относительно вашего параметра MEDIA_ROOT. Просто сохраните файл (вы можете использовать PIL для проверки его изображения) и заполните поле его именем.

Таким образом, он отличается от вашего кода тем, что вам нужно сохранить вывод вашего файла urllib.urlopen в файл (внутри вашего медиа-местоположения), выработать путь, сохранить его в своей модели.

Ответ 4

Я делаю это так на Python 3, который должен работать с простыми адаптациями на Python 2. Это основано на моих знаниях о том, что файлы Im retrieve малы. Если ваш arent, Id, вероятно, рекомендуется записать ответ в файл вместо буферизации в памяти.

BytesIO необходим, потому что Django вызывает seek() в файловом объекте, а ответы urlopen не поддерживают поиск. Вы можете передать объект байтов, возвращенный read(), в Django ContentFile.

from io import BytesIO
from urllib.request import urlopen

from django.core.files import File


# url, filename, model_instance assumed to be provided
response = urlopen(url)
io = BytesIO(response.read())
model_instance.image_field.save(filename, File(io))

Ответ 5

Объединив то, что Крис Адамс и Стэн сказали и обновили для работы над Python 3, если вы установите Requests, вы можете сделать что-то вроде это:

from urllib.parse import urlparse
import requests
from django.core.files.base import ContentFile
from myapp.models import Photo

img_url = 'http://www.example.com/image.jpg'
name = urlparse(img_url).path.split('/')[-1]

photo = Photo() # set any other fields, but don't commit to DB (ie. don't save())

response = requests.get(img_url)
if response.status_code == 200:
    photo.image.save(name, ContentFile(response.content), save=True)

Более релевантные документы в Документация Django ContentFile и Файл запросов Загрузить пример.

Ответ 6

это правильный и рабочий путь

class Product(models.Model):
    upload_path = 'media/product'
    image = models.ImageField(upload_to=upload_path, null=True, blank=True)
    image_url = models.URLField(null=True, blank=True)

    def save(self, *args, **kwargs):
        if self.image_url:
            import urllib, os
            from urlparse import urlparse
            filename = urlparse(self.image_url).path.split('/')[-1]
            urllib.urlretrieve(self.image_url, os.path.join(file_save_dir, filename))
            self.image = os.path.join(upload_path, filename)
            self.image_url = ''
            super(Product, self).save()

Ответ 7

Если вы используете функцию загрузки файлов в проекте Django, сначала установите Pillow:

pip install pillow==2.6.1

Не забудьте установить URL-адрес для файлов мультимедиа в settings.py:

MEDIA_ROOT = 'media/'

Затем в вашем файле models.py добавьте следующее поле изображения:

userlogo = models.ImageField(upload_to="userlogo/", blank=True, null=True)

После написания этого кода, перенесите модель, используя:

python manage.py makemigrations
python manage.py migrate

Теперь вы можете загружать файлы изображений с помощью поля изображения. Файлы изображений будут загружены в каталог YOUR_PROJECT_ROOT/media/userlogo. Вам dont необходимо создать папку userlogo вручную.