przepraszam za mój brzydki angielski ;-)
Wyobraź sobie ten bardzo prosty model:
class Photo(models.Model):
image = models.ImageField('Label', upload_to='path/')
Chciałbym stworzyć zdjęcie z adresu URL obrazu (tj. Nie ręcznie na stronie 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 dobrze wyjaśniłem problem, jeśli nie powiedz mi.
Dziękuję Ci :)
Edytować :
To może działać, ale nie wiem, jak przekonwertować content
na plik 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
przedmiotem pochodzących z?im
był nieco zwięzły - w tym przykładzieim
był instancją modelu ifile
była niewyobrażalną nazwą FileField / ImageField w tej instancji. Rzeczywista dokumentacja API tutaj ma znaczenie - ta technika powinna działać wszędzie tam, gdzie masz obiekt Django File powiązany z obiektem: docs.djangoproject.com/en/1.5/ref/files/file/ ...requests
zamiast tegourllib2
możesz zrobić:image_content = ContentFile(requests.get(url_image).content)
i wtedyobj.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)
źródło
Łącząc to, co powiedzieli Chris Adams i Stan i aktualizując rzeczy do pracy w Pythonie 3, jeśli zainstalujesz Requests , możesz 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)
Więcej odpowiednich dokumentów w dokumentacji Django ContentFile i przykładzie pobierania pliku żądań .
źródło
ImageField
jest po prostu ciągiem znaków, ścieżką względem twojegoMEDIA_ROOT
ustawienia. Po prostu zapisz plik (możesz użyć PIL, aby sprawdzić, czy jest to obraz) i wypełnij pole nazwą pliku.Więc różni się od twojego kodu tym, że musisz zapisać wyjście swojego
urllib.urlopen
pliku do pliku (wewnątrz lokalizacji nośnika), opracować ścieżkę, zapisać ją w swoim modelu.źródło
Robię to w ten sposób w Pythonie 3, który powinien działać z prostymi adaptacjami w Pythonie 2. Jest to oparte na mojej wiedzy, że pobrane pliki są małe. Jeśli nie, prawdopodobnie zaleciłbym zapisanie odpowiedzi do pliku zamiast buforowania w pamięci.
BytesIO jest potrzebne, ponieważ Django wywołuje funkcję seek () na obiekcie pliku, a odpowiedzi urlopen nie obsługują wyszukiwania. Zamiast tego można przekazać obiekt bytes zwrócony przez read () do ContentFile 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))
źródło
__repr__
metodaFile
zapisuje tę nazwę. Jeśli wolisz, możesz ustawićname
atrybut naFile
obiekcie po utworzeniu goFile(io)
, ale z mojego doświadczenia nie ma to znaczenia (poza tym, że ładniej wygląda, jeśli go wydrukujesz). ymmv.Ostatnio używam następującego podejścia w Pythonie 3 i Django 3, może to może być również interesujące dla innych. Jest podobny do rozwiązania Chrisa Adamsa, ale dla mnie już nie działał.
# -*- 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()
źródło
Właśnie odkryłem, że nie musisz generować pliku tymczasowego:
Przesyłaj zawartość URL bezpośrednio z django do minio
Muszę przechowywać moje pliki w minio i mieć kontenery docker django bez dużej ilości miejsca na dysku i konieczności pobierania dużych plików wideo, więc to było dla mnie bardzo pomocne.
źródło
to jest właściwy i działający sposób
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()
źródło