Django : 이미지 URL에서 ImageField에 이미지 추가


85

내 추악한 영어로 실례합니다 ;-)

이 매우 간단한 모델을 상상해보십시오.

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

이미지 URL에서 사진을 만들고 싶습니다 (즉, django 관리 사이트에서 손으로하지 않음).

다음과 같이해야한다고 생각합니다.

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)

말하지 않더라도 문제를 잘 설명했으면합니다.

감사합니다 :)

편집하다 :

이것은 작동 할 수 있지만 contentdjango 파일 로 변환하는 방법을 모르겠습니다 .

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)

답변:


96

이 같은 문제에 대해 방금 http://www.djangosnippets.org/snippets/1890/ 을 만들었습니다 . 이 코드는 urllib2.urlopen을 사용한다는 점을 제외하면 위의 pithyless '답변과 유사합니다. urllib.urlretrieve는 기본적으로 오류 처리를 수행하지 않으므로 필요한 내용 대신 404/500 페이지의 내용을 쉽게 얻을 수 있기 때문입니다. 콜백 함수 및 사용자 지정 URLOpener 하위 클래스를 만들 수 있지만 다음과 같이 내 임시 파일을 만드는 것이 더 쉽다는 것을 알았습니다.

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
마지막 라인은 무엇을하고 있습니까? 무엇 im에서 오는 목적은?
priestc

1
@priestc : im약간 간결했습니다.이 예제에서는 im모델 인스턴스 file였으며 해당 인스턴스 의 FileField / ImageField의 상상할 수없는 이름이었습니다. 여기에 실제 API 문서는 무슨 일이 있어도이다 - 기술은 사용자가 객체에 장고 파일 객체를 결합했다 어디서든 일을해야 : docs.djangoproject.com/en/1.5/ref/files/file/...
크리스 아담스

26
임시 파일은 필요하지 않습니다. 사용 requests대신에 urllib2: 당신은 할 수있는 image_content = ContentFile(requests.get(url_image).content)다음과 obj.my_image.save("foo.jpg", image_content).
Stan

스탠 : 요청은 raise_for_status (라고 않는 한 IIRC가 한 줄 먼저 오류 또는 불완전 반응과 피할 혼란에) 문제가 될 것이라고 것을 단순화 않습니다
크리스 아담스

원래 Django 1.1 / 1.2 시대로 작성되었으므로이를 현대화하는 것이 좋습니다. 즉, ContentFile에는 전체 파일을 메모리에로드하는 문제가 여전히 있다고 생각하므로 좋은 최적화는 합리적인 청크 크기로 iter_content를 사용하는 것입니다.
Chris Adams

32

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)


안녕하세요, 도와 주셔서 감사합니다;). 문제는 (문서 인용) : "내용 인수는 File의 인스턴스이거나 File의 하위 클래스 여야합니다."입니다. 콘텐츠로 파일 인스턴스를 만드는 솔루션이 있습니까?

새 편집을 확인하십시오. (나는 그것을 테스트하지 않은 있지만)이 이제 작업을 예를해야한다
pithyless

다른 분야도있는 내 모델은 어떻습니까? url, etc, 등등과 같습니다. id라면 model.image.save (...). 다른 필드는 어떻게 저장합니까? 그들은 null 일 수 없습니다. 편집 : woudl 그것은 이와 같은 것입니까? >>> car.photo.save ( 'myphoto.jpg', contents, save = False) >>> car.save ()
Harry

self.url ?? ... 여기서 self.url은 무엇입니까 ??
DeadDjangoDjoker

@DeadDjangoDjoker 잘 모르겠습니다. 내 대답을 편집 한 사람에게 물어봐야합니다. 이 답변은이 시점에서 5 년이되었습니다. 나는 후손을 위해 이전의 "작동하는"솔루션으로 되돌 렸지만 솔직히 Chris Adam의 대답을 사용하는 것이 좋습니다.
pithyless

13

Chris Adams와 Stan이 말한 것을 결합하고 Python 3에서 작동하도록 업데이트하면 Requests 를 설치 하면 다음과 같이 할 수 있습니다.

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)

Django의 ContentFile 문서Requests의 파일 다운로드 예제 에서 더 관련있는 문서 .


5

ImageFieldMEDIA_ROOT설정에 상대적인 경로 인 문자열 입니다. 파일을 저장하고 (PIL을 사용하여 이미지인지 확인하고 싶을 수 있음) 필드를 파일 이름으로 채 웁니다.

따라서 출력 urllib.urlopen을 파일 (미디어 위치 내부)에 저장하고 경로를 확인하고 모델 에 저장해야한다는 점에서 코드와 다릅니다 .


5

저는 Python 3에서 이렇게합니다.이 방법은 Python 2에서 간단한 개조로 작동합니다. 이것은 제가 검색하는 파일이 작다는 제 지식을 기반으로합니다. 그렇지 않은 경우 메모리 버퍼링 대신 파일에 응답을 작성하는 것이 좋습니다.

Django는 파일 객체에서 seek ()를 호출하고 urlopen 응답은 검색을 지원하지 않기 때문에 BytesIO가 필요합니다. read ()가 반환 한 bytes 객체를 Django의 ContentFile에 대신 전달할 수 있습니다.

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))

파일 (IO) 반환 <파일 : 없음>
Susaj S 나이 르

@SusajSNair 파일에 이름이 없기 때문에 이름 __repr__File쓰는 방법입니다 . 원하는 경우를 사용 name하여 File개체를 만든 후 개체에 속성을 설정할 수 File(io)있지만 내 경험상 중요하지 않습니다 (인쇄하면 더보기 좋게 만드는 것 외에는 제외). ymmv.
jbg

3

최근에 저는 파이썬 3과 장고 3에서 다음과 같은 접근 방식을 사용합니다. 아마도 이것은 다른 사람들에게도 흥미로울 것입니다. Chris Adams 솔루션과 유사하지만 더 이상 작동하지 않았습니다.

# -*- 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()

이것은 나를 위해 일한 유일한 솔루션입니다 (Python 3 + Django 2). 다소 사소한 설명은 URL에 따라 basename에 모든 경우에 올바른 확장자가 없을 수 있다는 것입니다.
physicsAI

1

임시 파일을 생성 할 필요가 없다는 것을 방금 발견했습니다.

django에서 minio로 직접 URL 콘텐츠 스트리밍

내 파일을 minio에 저장하고 디스크 공간없이 django docker 컨테이너를 가져야하고 큰 비디오 파일을 다운로드해야했기 때문에 이것은 나에게 정말 도움이되었습니다.


-5

이것이 옳고 일하는 방법입니다

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()

14
그것은 올바른 방법이 될 수 없습니다. FielField의 전체 파일 저장 메커니즘을 우회하고 저장 API를 존중하지 않습니다.
Andre Bossard
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.