por favor disculpe mi feo inglés ;-)
Imagina este modelo muy simple:
class Photo(models.Model):
image = models.ImageField('Label', upload_to='path/')
Me gustaría crear una foto a partir de una URL de imagen (es decir, no a mano en el sitio de administración de django).
Creo que necesito hacer algo como esto:
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)
Espero haberte explicado bien el problema, si no me lo dices.
Gracias :)
Editar:
Esto puede funcionar, pero no sé cómo convertir content
a un archivo 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
objeto?im
fue un poco conciso; en ese ejemplo,im
era la instancia del modelo yfile
era el nombre poco imaginativo de un FileField / ImageField en esa instancia. Los documentos de API reales aquí son lo que importa: esa técnica debería funcionar en cualquier lugar donde tenga un objeto de archivo Django vinculado a un objeto: docs.djangoproject.com/en/1.5/ref/files/file/…requests
lugar deurllib2
usted puede hacer:image_content = ContentFile(requests.get(url_image).content)
y luegoobj.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)
fuente
Combinando lo que Chris Adams y Stan dijeron y actualizando las cosas para que funcionen en Python 3, si instalas Requests puedes hacer algo como esto:
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)
Documentos más relevantes en la documentación de ContentFile de Django y el ejemplo de descarga de archivos de solicitudes .
fuente
ImageField
es solo una cadena, una ruta relativa a suMEDIA_ROOT
configuración. Simplemente guarde el archivo (es posible que desee usar PIL para verificar que sea una imagen) y complete el campo con su nombre de archivo.Por lo tanto, se diferencia de su código en que necesita guardar la salida de su
urllib.urlopen
archivo a (dentro de su ubicación de medios), calcular la ruta y guardarla en su modelo.fuente
Lo hago de esta manera en Python 3, que debería funcionar con adaptaciones simples en Python 2. Esto se basa en mi conocimiento de que los archivos que estoy recuperando son pequeños. Si el tuyo no lo es, probablemente recomiendo escribir la respuesta en un archivo en lugar de almacenarla en la memoria.
Se necesita BytesIO porque Django llama a seek () en el objeto de archivo y las respuestas de urlopen no admiten la búsqueda. En su lugar, podría pasar el objeto bytes devuelto por read () al ContentFile de 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))
fuente
__repr__
método paraFile
escribe el nombre. Si lo prefiere, puede establecer elname
atributo en elFile
objeto después de crearloFile(io)
, pero en mi experiencia no importa (aparte de hacer que se vea mejor si lo imprime). mmmv.Recientemente utilicé el siguiente enfoque dentro de Python 3 y Django 3, tal vez esto también pueda ser interesante para otros. Es similar a la solución de Chris Adams pero para mí ya no funcionó.
# -*- 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()
fuente
Acabo de descubrir que no es necesario generar un archivo temporal:
Transmita contenido de URL directamente desde django a minio
Tengo que almacenar mis archivos en minio y tener contenedores Docker de django sin mucho espacio en el disco y necesito descargar archivos de video grandes, así que esto fue realmente útil para mí.
fuente
esta es la forma correcta y funcional
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()
fuente