2009-09-08 41 views
73

quiero disculparme por mi fea Inglés ;-)Django: agregar la imagen en una imagen de ImageField url

Imagínese este modelo muy simple:

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

Me gustaría crear una foto de una imagen URL (es decir, no a mano en el sitio de administración de django).

creo que tengo que 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 que he explicado bien el problema, si no dime.

Gracias :)

Editar:

Esto puede funcionar, pero no sé cómo convertir un archivo content a 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) 

Respuesta

5

ImageField es sólo una cadena, una ruta relativa a su configuración MEDIA_ROOT. Simplemente guarde el archivo (es posible que desee usar PIL para verificar que sea una imagen) y rellene el campo con su nombre de archivo.

Por lo tanto, difiere de su código en que necesita guardar la salida de su urllib.urlopen en un archivo (dentro de la ubicación de su medio), busque la ruta, guárdela en su modelo.

27
 

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) 
 
+0

Hola, gracias por ayudarme;). El problema es (cito el documento): "Tenga en cuenta que el argumento de contenido debe ser una instancia de File o de una subclase de File". Entonces, ¿tienes alguna solución para crear una instancia de archivo con tu contenido? –

+0

Verifica la nueva edición; esto debería ser ahora un ejemplo de trabajo (aunque no lo he probado) – pithyless

+0

¿Qué pasa con mi modelo, donde también tengo otros campos? Como url, etc., etc. Si id do model.image.save (...). ¿Cómo guardo los otros campos? No pueden ser nulos EDITAR: ¿Será algo como esto? >>> car.photo.save ('myphoto.jpg', contenido, guardar = False) >>> car.save() – Harry

92

Acabo de crear http://www.djangosnippets.org/snippets/1890/ para este mismo problema. El código es similar a la respuesta sin contenido anterior, excepto que usa urllib2.urlopen porque urllib.urlretrieve no realiza ningún manejo de errores de manera predeterminada, por lo que es fácil obtener el contenido de una página 404/500 en lugar de lo que necesita. Puede crear la función de devolución de llamada subclase URLOpener & costumbre, pero me pareció más fácil sólo para crear mi propio archivo temporal como esto:

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)) 
+3

¿qué está haciendo la última línea? ¿de qué viene el objeto 'im'? – priestc

+1

@priestc: 'im' fue un poco escueto; en ese ejemplo,' im' era la instancia del modelo y 'file' era el nombre poco imaginativo de un FileField/ImageField en esa instancia. Los documentos API actuales aquí son lo que importa, esa técnica debería funcionar en cualquier lugar donde tenga un objeto Django File vinculado a un objeto: https://docs.djangoproject.com/en/1.5/ref/files/file/#django.core. files.File.save –

+22

No es necesario un archivo temporal. Usando 'requests' en lugar de' urllib2' puedes hacer: 'image_content = ContentFile (requests.get (url_image) .content)' y luego 'obj.my_image.save (" foo.jpg ", image_content)'. – Stan

-1

este es el derecho y el trabajo forma

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() 
+11

No puede ser el camino correcto, elude todo el mecanismo de almacenamiento de archivos de FielField y no le paga a la API de almacenamiento. –

4

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 recomendaría escribir la respuesta en un archivo en lugar de almacenarla en la memoria.

BytesIO es necesario porque Django llama a seek() en el objeto de archivo, y las respuestas de urlopen no son compatibles con la búsqueda. Podría pasar el objeto bytes devuelto por read() al ContentFile de Django en su lugar.

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)) 
-3

Si está utilizando la función de carga de archivos en su proyecto de Django, debe instalar primero Almohada:

pip install pillow==2.6.1 

Recuerde que debe establecer la dirección URL de archivos multimedia en settings.py:

MEDIA_ROOT = 'media/' 

Luego, en sus modelos.py, agregue el siguiente campo de la imagen:

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

Después de escribir el código, migrar el modelo usando:

python manage.py makemigrations 
python manage.py migrate 

Ahora puedes subir archivos de imagen utilizando el campo de la imagen. Los archivos de imagen se subirían al directorio YOUR_PROJECT_ROOT/media/userlogo. Usted no necesita crear manualmente la carpeta 'userlogo'.

+0

Esto no responde la pregunta del OP. Él ya tiene el campo de imagen configurado y funcionando. Necesitaba obtener programáticamente el contenido de la imagen de una URL y guardarlo en un 'ImageField'. –

2

Combinando lo dijo Chris Adams y Stan y la actualización de las cosas para trabajar en Python 3, si instala Requests se puede 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 Django's ContentFile documentation y Requests' file download ejemplo.

Cuestiones relacionadas