2009-09-08 27 views
73

xin vui lòng cho tôi xin lỗi cho tôi xấu xí tiếng anh ;-)Django: thêm hình ảnh trong một ImageField từ url hình ảnh

Hãy tưởng tượng mô hình rất đơn giản này:

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

Tôi muốn tạo ra một hình ảnh từ một hình ảnh URL (ví dụ: không phải bằng tay trong trang web quản trị django).

Tôi nghĩ rằng tôi cần phải làm một cái gì đó như thế này:

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) 

Tôi hy vọng rằng tôi đã giải thích tốt các vấn đề, nếu không muốn nói cho tôi biết.

Cảm ơn bạn :)

Edit:

này có thể làm việc nhưng tôi không biết làm thế nào để chuyển đổi content đến một tập tin 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) 

Trả lời

5

ImageField chỉ là một chuỗi, một đường dẫn tương đối với cài đặt MEDIA_ROOT của bạn. Chỉ cần lưu tệp (bạn có thể muốn sử dụng PIL để kiểm tra nó là một hình ảnh) và điền vào trường bằng tên tệp của nó.

Vì vậy, nó khác với mã của bạn ở chỗ bạn cần lưu đầu ra của urllib.urlopen vào tệp (bên trong vị trí phương tiện), tạo ra đường dẫn, lưu nó vào mô hình của bạn.

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

Xin chào, cảm ơn vì đã giúp tôi;). Vấn đề là (tôi trích dẫn tài liệu): "Lưu ý rằng đối số nội dung phải là một phiên bản của Tệp hoặc của một lớp con của Tệp." Vì vậy, bạn có bất kỳ giải pháp để tạo ra tập tin dụ với nội dung của bạn? –

+0

Kiểm tra chỉnh sửa mới; điều này bây giờ sẽ là một ví dụ làm việc (mặc dù tôi đã không thử nghiệm nó) – pithyless

+0

Điều gì về mô hình của tôi, nơi tôi có các lĩnh vực khác là tốt. Giống như url, v.v. Nếu id làm model.image.save (...). làm cách nào để lưu các trường khác? Họ không thể được null EDIT: woudl nó là một cái gì đó như thế này? >>> car.photo.save ('myphoto.jpg', nội dung, lưu = False) >>> car.save() – Harry

92

tôi vừa tạo http://www.djangosnippets.org/snippets/1890/ cho vấn đề này giống nhau. Các mã tương tự như pithyless 'câu trả lời ở trên ngoại trừ nó sử dụng urllib2.urlopen vì urllib.urlretrieve không thực hiện bất kỳ xử lý lỗi theo mặc định vì vậy nó dễ dàng để có được nội dung của một trang 404/500 thay vì những gì bạn cần. Bạn có thể tạo hàm callback URLOpener lớp con & tùy chỉnh nhưng tôi tìm thấy nó dễ dàng hơn chỉ để tạo tập tin tạm thời của riêng tôi như thế này:

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

dòng cuối cùng là gì? đối tượng 'im' đến từ đâu? – priestc

+1

@priestc: 'im' là một chút terse - trong ví dụ đó,' im' là instance mẫu và 'file' là tên không tưởng tượng của một FileField/ImageField trên cá thể đó. Các tài liệu API thực tế ở đây là những gì quan trọng - kỹ thuật đó sẽ làm việc bất cứ nơi nào bạn có một đối tượng File Django ràng buộc với một đối tượng: https://docs.djangoproject.com/en/1.5/ref/files/file/#django.core. files.File.save –

+22

Tệp tạm thời là không cần thiết. Sử dụng 'requests' thay vì' urllib2' bạn có thể làm: 'image_content = ContentFile (requests.get (url_image) .content)' và sau đó 'obj.my_image.save (" foo.jpg ", image_content)'. – Stan

-1

này là quyền và làm việc theo cách

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

Đó không phải là cách đúng đắn, bạn phá vỡ toàn bộ cơ chế lưu trữ tệp của FielField và không trả tiền cho việc lưu trữ api. –

4

tôi làm theo cách này trên Python 3, mà nên làm việc với các thích ứng đơn giản trên Python 2. Điều này dựa trên kiến ​​thức của tôi rằng các tập tin tôi đang lấy là nhỏ. Nếu không phải của bạn, tôi có thể khuyên bạn nên viết câu trả lời cho một tệp thay vì đệm trong bộ nhớ.

BytesIO là cần thiết vì cuộc gọi Django tìm kiếm() trên đối tượng tệp và phản hồi urlopen không hỗ trợ tìm kiếm. Bạn có thể vượt qua đối tượng byte trả về bằng cách đọc() để ContentFile của Django thay vào đó.

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

Nếu bạn đang sử dụng tính năng tải lên tập tin trong dự án Django của bạn, bạn phải cài đặt Gối đầu tiên:

pip install pillow==2.6.1 

Hãy nhớ để thiết lập các url cho các tập tin media trong settings.py:

MEDIA_ROOT = 'media/' 

Sau đó, trong các kiểu máy của bạn.py, thêm lĩnh vực hình ảnh sau đây:

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

Sau khi viết mã này, di chuyển các mô hình sử dụng:

python manage.py makemigrations 
python manage.py migrate 

Bây giờ bạn có thể tải tập tin hình ảnh bằng cách sử dụng lĩnh vực hình ảnh. Các tệp hình ảnh sẽ được tải lên thư mục YOUR_PROJECT_ROOT/media/userlogo. Bạn không cần tạo thư mục 'userlogo' theo cách thủ công.

+0

Điều này không trả lời câu hỏi của OP. Anh ta đã thiết lập và làm việc lĩnh vực hình ảnh. Anh ta cần phải lập trình lấy nội dung hình ảnh từ một URL và lưu nó vào một 'ImageField'. –

2

Kết hợp những gì Chris Adams và Stan nói và cập nhật mọi thứ để làm việc trên Python 3, nếu bạn cài đặt Requests bạn có thể làm một cái gì đó như thế này:

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) 

tài liệu có liên quan khác trong Django's ContentFile documentationRequests' file download ví dụ.

Các vấn đề liên quan