2009-09-08 6 views
73

proszę wybaczcie mi za brzydki angielsku ;-)Django: dodawanie obrazu w ImageField z URL obrazu

Wyobraź to bardzo prosty model:

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

chciałbym stworzyć zdjęcie z obrazem URL (tj. Nie ręcznie w witrynie administratora django).

myślę, że muszę zrobić coś takiego:

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) 

Mam nadzieję, że ja również wyjaśnić ten problem, jeśli nie mów.

Dziękuję :)

Edit:

To może działać, ale nie wiem jak konwertować content do pliku 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) 

Odpowiedz

5

ImageField tylko Powrózek, ścieżkę względem ustawienia MEDIA_ROOT. Po prostu zapisz plik (możesz użyć PIL, aby sprawdzić, czy jest obrazem) i wypełnij pole jego nazwą.

Tak więc różni się on od kodu tym, że musisz zapisać dane wyjściowe pliku urllib.urlopen (w lokalizacji multimediów), opracować ścieżkę, zapisać ją w swoim modelu.

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

Cześć, dziękuję za pomoc;). Problem polega na tym (cytuję dokument): "Zauważ, że argument content musi być instancją File lub podklasy File." Czy masz jakieś rozwiązanie do tworzenia instancji File z zawartością? –

+0

Sprawdź nową zmianę; powinien to być teraz działający przykład (chociaż tego nie testowałem). – pithyless

+0

Co z moim modelem, gdzie mam inne pola. Jak adres URL, itp., Itp. Jeśli id ​​to model.image.save (...). jak zapisać pozostałe pola? Nie mogą być nieważne EDYCJA: woudl to coś takiego? >>> car.photo.save ('myphoto.jpg', zawartość, save = False) >>> car.save() – Harry

92

Właśnie stworzyłem http://www.djangosnippets.org/snippets/1890/ dla tego samego problemu. Kod jest podobny do "bezbłędnej" odpowiedzi powyżej, z wyjątkiem tego, że używa urllib2.urlopen, ponieważ urllib.urlretrieve nie wykonuje domyślnie obsługi błędów, więc łatwo jest uzyskać zawartość strony 404/500 zamiast tego, co jest potrzebne. Można utworzyć funkcję zwrotną & niestandardową URLOpener podklasy, ale okazało się, że łatwiej jest stworzyć własny plik temp takiego:

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

co robi ostatnia linia? z czego pochodzi obiekt 'im'? – priestc

+1

@priestc: 'im' było trochę zwięzłe - w tym przykładzie instancja modelu to" im ", a" file "to niewyobrażalna nazwa FileField/ImageField na tej instancji. Rzeczywiste dokumenty API tutaj mają znaczenie - ta technika powinna działać wszędzie tam, gdzie obiekt Django File jest powiązany z obiektem: https://docs.djangoproject.com/en/1.5/ref/files/file/#django.core. files.File.save –

+22

Plik tymczasowy jest niepotrzebny. Używając 'requests' zamiast' urllib2', możesz: 'image_content = ContentFile (requests.get (url_image) .content)' a następnie 'obj.my_image.save (" foo.jpg ", image_content)'. – Stan

-1

to jest właściwe i pracy sposobem

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

To nie może być właściwa droga, omijasz cały mechanizm przechowywania plików FielField i nie przestrzegasz api przechowywania. –

4

zrobić to w ten sposób na Pythonie 3, który powinien działać z prostymi adaptacjami w Pythonie 2. Jest to oparte na mojej wiedzy, że pliki, które pobieram są małe. Jeśli tak nie jest, prawdopodobnie zaleciłbym zapisanie odpowiedzi do pliku zamiast buforowania w pamięci.

BytesIO jest potrzebny, ponieważ Django wywołuje seek() na obiekcie pliku, a urlopen odpowiedzi nie wspierają wyszukiwania. Można przekazać obiekt bajtów zwrócony przez read() do pliku ContentDome 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

Jeśli używasz funkcji przesyłania plików w projekcie Django, musisz zainstalować Pillow pierwszy:

pip install pillow==2.6.1 

Pamiętaj, aby ustawić adres URL do plików multimedialnych w settings.py:

MEDIA_ROOT = 'media/' 

Następnie w swoich modelach.py, dodać następujące pola obrazu:

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

Po wpisaniu tego kodu, migrują model używając:

python manage.py makemigrations 
python manage.py migrate 

Teraz można przesyłać pliki obrazów przy użyciu pola obrazu. Pliki obrazów zostaną przesłane do katalogu YOUR_PROJECT_ROOT/media/userlogo. Musisz dont musisz ręcznie utworzyć folder "userlogo".

+0

To nie odpowiada na pytanie OP. Ma już skonfigurowane i działające pole obrazu. Musiał programowo pobrać zawartość obrazu z adresu URL i zapisać go do 'ImageField'. –

2

Łącząc co Chris Adams i Stan powiedział i aktualizowanie rzeczy do pracy w Pythonie 3, jeśli zainstalować Requests można zrobić coś takiego:

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) 

trafniejsze docs w Django's ContentFile documentation i Requests' file download przykład.