пожалуйста, извините за мой уродливый английский ;-)
Представьте себе эту очень простую модель:
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)
im
исходит объект?im
было немного кратко - в этом примере этоim
был экземпляр модели, аfile
имя FileField / ImageField в этом экземпляре было невообразимым. Фактические документы API здесь имеют значение - этот метод должен работать везде, где у вас есть объект Django File, привязанный к объекту: docs.djangoproject.com/en/1.5/ref/files/file/…requests
вместоurllib2
вы можете:image_content = ContentFile(requests.get(url_image).content)
а затемobj.my_image.save("foo.jpg", image_content)
.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)
источник
Объединив то, что сказали Крис Адамс и Стэн, и обновив вещи для работы на 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 и в примере загрузки файла Requests .
источник
ImageField
это просто строка, путь относительно вашейMEDIA_ROOT
настройки. Просто сохраните файл (вы можете использовать PIL, чтобы проверить, что это изображение) и заполните поле его именем.Таким образом, он отличается от вашего кода тем, что вам нужно сохранить вывод вашего
urllib.urlopen
файла (внутри вашего местоположения мультимедиа), определить путь, сохранить его в своей модели.источник
Я делаю это на Python 3, который должен работать с простой адаптацией на Python 2. Это основано на моих знаниях о том, что файлы, которые я получаю, небольшие. Если у вас нет, я бы, вероятно, рекомендовал записать ответ в файл вместо буферизации в памяти.
BytesIO необходим, потому что Django вызывает функцию seek () для объекта файла, а ответы urlopen не поддерживают поиск. Вместо этого вы можете передать объект байтов, возвращаемый read (), в ContentFile Django.
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))
источник
__repr__
метод дляFile
записи имени. Если хотите, вы можете установитьname
атрибут дляFile
объекта после его созданияFile(io)
, но, по моему опыту, это не имеет значения (кроме того, чтобы он выглядел лучше, если вы его распечатаете). ymmv.В последнее время я использую следующий подход в Python 3 и Django 3, возможно, это может быть интересно и другим. Это похоже на решение Криса Адамса, но для меня оно больше не работает.
# -*- coding: utf-8 -*- import urllib.request from django.core.files.uploadedfile import SimpleUploadedFile from urllib.parse import urlparse from demoapp import models img_url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Stack_Overflow_logo.png' basename = urlparse(img_url).path.split('/')[-1] tmpfile, _ = urllib.request.urlretrieve(img_url) new_image = models.ModelWithImageOrFileField() new_image.attribute_a = True new_image.attribute_b = 'False' new_image.file = SimpleUploadedFile(basename, open(tmpfile, "rb").read()) new_image.save()
источник
Только что обнаружил, что вам не нужно создавать временный файл:
Потоковая передача содержимого url прямо из django в minio
Мне нужно хранить свои файлы в minio и иметь контейнеры докеров django без много места на диске и мне нужно загружать большие видеофайлы, так что это было действительно полезно для меня.
источник
это правильный и рабочий способ
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()
источник