2009-09-08 13 views
73

Ti prego di scusarmi per la mia brutta inglese ;-)Django: aggiungi l'immagine in un ImageField dall'immagine url

immaginare questo modello molto semplice:

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

Vorrei creare una foto da un'immagine URL (cioè, non a mano nel sito admin di Django).

Penso che ho bisogno di fare qualcosa di simile:

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) 

Spero che ho ben spiegato il problema, se non me lo dica.

voi :) Grazie

Edit:

Questo può funzionare, ma non so come convertire content in un file 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) 

risposta

5

ImageField è solo una stringa, un percorso relativo all'impostazione MEDIA_ROOT. Basta salvare il file (si potrebbe voler usare PIL per controllare che sia un'immagine) e popolare il campo con il suo nome file.

Quindi, differisce dal codice in quanto è necessario salvare l'output del file urllib.urlopen in file (all'interno della posizione del supporto), calcolare il percorso, salvarlo nel modello.

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

Ciao, grazie per avermi aiutato;). Il problema è (cito il documento): "Si noti che l'argomento del contenuto deve essere un'istanza di File o di una sottoclasse di File." Quindi hai qualche soluzione per creare un'istanza File con i tuoi contenuti? –

+0

Controlla la nuova modifica; questo dovrebbe ora essere un esempio funzionante (anche se non l'ho ancora testato) – pithyless

+0

E il mio modello, dove ho anche altri campi. Come url, ecc, ecc. Se id esegue model.image.save (...). come faccio a salvare gli altri campi? Non possono essere nulli EDIT: woudl sarà qualcosa del genere? >>> car.photo.save ('myphoto.jpg', contenuto, save = False) >>> car.save() – Harry

92

Ho appena creato http://www.djangosnippets.org/snippets/1890/ per questo stesso problema. Il codice è simile alla risposta precedente senza l'uso di urllib2.urlopen perché urllib.urlretrieve non esegue alcuna gestione degli errori per impostazione predefinita, quindi è facile ottenere il contenuto di una pagina 404/500 invece di quello che ti serve. È possibile creare la funzione di callback URLopener sottoclasse & personalizzato ma ho trovato più facile solo per creare il mio file temporaneo in questo modo:

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

cosa sta facendo l'ultima linea? da dove viene l'oggetto 'im'? – priestc

+1

@priestc: 'im' era un po 'conciso - in quell'esempio,' im' era l'istanza del modello e 'file' era il nome privo di fantasia di un FileField/ImageField su quell'istanza. I documenti API effettivi qui sono ciò che importa - quella tecnica dovrebbe funzionare ovunque tu abbia un oggetto Django File legato ad un oggetto: https://docs.djangoproject.com/en/1.5/ref/files/file/#django.core. files.File.save –

+22

Un file temporaneo non è necessario. Usando 'requests' invece di' urllib2' puoi fare: 'image_content = ContentFile (requests.get (url_image) .content)' e poi 'obj.my_image.save (" foo.jpg ", image_content)'. – Stan

-1

questo è il diritto e di lavoro modo

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

Questo non può essere il modo giusto, si elude l'intero meccanismo di archiviazione dei file di FielField e non si paga alcun rispetto per l'API di archiviazione. –

4

lo faccio in questo modo su Python 3, che dovrebbe funzionare con semplici adattamenti su Python 2. Ciò è basato sulla mia conoscenza che i file che sto recuperando sono piccoli. Se non lo sono, probabilmente raccomanderei di scrivere la risposta su un file invece di eseguire il buffering in memoria.

BytesIO è necessario perché Django chiama seek() sull'oggetto file e le risposte urlopen non supportano la ricerca. Potresti passare invece l'oggetto bytes restituito da read() a ContentFile di 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)) 
-3

Se si utilizza funzionalità di upload di file nel progetto Django, è necessario installare prima Pillow:

pip install pillow==2.6.1 

ricordarsi di impostare l'URL per i file multimediali in settings.py:

MEDIA_ROOT = 'media/' 

Quindi, nei tuoi modelli.py, aggiungere il seguente campo di immagine:

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

Dopo aver scritto questo codice, eseguire la migrazione del modello utilizzando:

python manage.py makemigrations 
python manage.py migrate 

Ora è possibile caricare file di immagine utilizzando il campo di immagine. I file immagine verrebbero caricati nella directory YOUR_PROJECT_ROOT/media/userlogo. È necessario creare manualmente la cartella 'userlogo'.

+0

Questo non risponde alla domanda dell'OP. Ha già il campo immagine impostato e funzionante. Aveva bisogno di ottenere a livello di codice il contenuto dell'immagine da un URL e salvarlo in un 'ImageField'. –

2

La combinazione di quello che hanno detto Chris Adams e Stan e aggiornando le cose a lavorare su Python 3, se si installa Requests si può fare qualcosa di simile:

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) 

documenti più rilevante nel Django's ContentFile documentation e Requests' file download esempio.

Problemi correlati