2009-09-08 9 views
73

bitte entschuldigen Sie mich für meine hässliche Englisch ;-)Django: add Bild in einem Imagefield von Bild-URL

dieses sehr einfaches Modell Stellen Sie sich vor:

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

Ich möchte ein Foto von einem Bild erstellen URL (dh nicht von Hand in der Django Admin-Site).

Ich denke, dass ich so etwas wie dies tun müssen:

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) 

Ich hoffe, dass ich auch das Problem erklärt, wenn nicht mir sagen. Danke

:)

Edit:

Diese arbeiten kann, aber ich weiß nicht, wie content zu einer django Datei zu konvertieren:

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) 

Antwort

5

ImageField ist nur eine Zeichenfolge, eine Pfad relativ zu Ihrer MEDIA_ROOT Einstellung. Speichern Sie die Datei einfach (Sie können PIL verwenden, um zu überprüfen, ob es ein Bild ist) und das Feld mit seinem Dateinamen füllen.

So unterscheidet es sich von Ihrem Code darin, dass Sie die Ausgabe Ihrer urllib.urlopen in Datei speichern müssen (in Ihrem Medienstandort), erarbeiten Sie den Pfad, speichern Sie das zu Ihrem Modell.

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

Hallo, danke, dass du mir geholfen hast;). Das Problem ist (ich zitiere das Dokument): "Beachten Sie, dass das Inhaltsargument eine Instanz von File oder einer Unterklasse von File sein muss." Haben Sie eine Lösung, um eine Dateiinstanz mit Ihren Inhalten zu erstellen? –

+0

Überprüfen Sie die neue Bearbeitung; das sollte jetzt ein funktionierendes Beispiel sein (obwohl ich es nicht getestet habe) – pithyless

+0

Was ist mit meinem Modell, wo ich auch andere Felder habe. Wie URL, etc, etc. Wenn id tun model.image.save (...). Wie speichere ich die anderen Felder? Sie können nicht null sein EDIT: Woudl es so etwas wie das sein? >>> car.photo.save ('myphoto.jpg', Inhalt, save = Falsch) >>> car.save() – Harry

92

Ich habe gerade http://www.djangosnippets.org/snippets/1890/ für das gleiche Problem erstellt. Der Code ähnelt der obigen Antwort "pithyless", mit der Ausnahme, dass urllib2.urlopen verwendet wird, da urllib.urlretrieve standardmäßig keine Fehlerbehandlung durchführt. Daher ist es einfach, den Inhalt einer 404/500-Seite anstatt der benötigten zu erhalten. Sie können Callback-Funktion & benutzerdefinierte URLOpener Unterklasse erstellen, aber ich fand es einfacher, nur meine eigene temporäre Datei wie diese zu erstellen:

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

Was macht die letzte Zeile? Woher kommt das 'im' Objekt? – priestc

+1

@priestc: 'im' war ein bisschen knapp - in diesem Beispiel war' im' die Modellinstanz und 'file' war der einfallslose Name eines FileField/ImageField für diese Instanz. Die eigentlichen API-Dokumente sind hier wichtig - diese Technik sollte überall funktionieren, wo ein Django-Dateiobjekt an ein Objekt gebunden ist: https://docs.djangoproject.com/en/1.5/ref/files/file/#django.core. files.File.save –

+22

Eine temporäre Datei ist nicht erforderlich. Mit 'requests' anstelle von' urllib2' können Sie: 'image_content = ContentFile (requests.get (url_image) .content)' und dann 'obj.my_image.save (" foo.jpg ", image_content)'. – Stan

-1

dies die richtige ist und Arbeits Weg

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

Das kann nicht der richtige Weg sein, Sie umgehen den gesamten Dateispeichermechanismus des FielField und zahlen keinen Respekt für die Speicher-API. –

4

ich es auf diese Weise auf Python 3, die mit einfachen Anpassungen auf Python 2 funktionieren sollte. Dies basiert auf meinem Wissen, dass die Dateien, die ich abrufe, klein sind. Wenn dies nicht der Fall ist, würde ich wahrscheinlich empfehlen, die Antwort in eine Datei zu schreiben, anstatt sie im Speicher zu puffern.

BytesIO wird benötigt, weil Django das Dateiobjekt seek() aufruft und urlopen-Antworten die Suche nicht unterstützen. Sie könnten stattdessen das von read() zurückgegebene bytes-Objekt an Djangos ContentFile übergeben.

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

Wenn Sie Datei-Upload-Funktion in Ihrem Django-Projekt verwenden, müssen Sie Kissen zuerst installieren:

pip install pillow==2.6.1 

Denken Sie daran, die URL für Mediendateien in settings.py einzustellen:

MEDIA_ROOT = 'media/' 

Dann in Ihren Modellen.py, fügen Sie das folgende Bildfeld:

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

Nach diesem Code zu schreiben, wandern mit dem Modell:

python manage.py makemigrations 
python manage.py migrate 

Jetzt können Sie Bilddateien mit dem Bildfeld laden. Die Bilddateien werden in das Verzeichnis YOUR_PROJECT_ROOT/media/userlogo hochgeladen. Sie dont müssen den 'userlogo' Ordner manuell erstellen.

+0

Dies beantwortet die Frage des OP nicht. Er hat bereits das Bildfeld eingerichtet und funktioniert. Er musste den Bildinhalt programmgesteuert von einer URL abrufen und in einem ImageField speichern. –

2

Kombination, was Chris Adams und Stan sagte und Dinge Aktualisierung auf Python arbeiten 3, wenn Sie Requests installieren Sie so etwas tun kann:

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) 

Weitere relevante Dokumente in Django's ContentFile documentation und Requests' file download Beispiel.

Verwandte Themen