web-dev-qa-db-ja.com

Django:画像のURLからImageFieldに画像を追加する

私のい英語を許してください;-)

この非常に単純なモデルを想像してください:

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

画像URLから写真を作成したい(つまり、Django adminサイト)に手でではない)。

私はこのようなことをする必要があると思います:

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)

教えてくれないにしても、問題をうまく説明できたらいいなと思っています。

ありがとうございました :)

編集:

これは動作するかもしれませんが、contentをDjango Fileに変換する方法がわかりません:

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

この同じ問題に対して http://www.djangosnippets.org/snippets/1890/ を作成しました。 urllib.urlretrieveはデフォルトではエラー処理を行わないため、必要なものではなく404/500ページのコンテンツを簡単に取得できるため、このコードは上記のpithylessの回答に似ています。コールバック関数とカスタム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))
95
Chris Adams

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

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ドキュメンテーション および リクエストのファイルダウンロード の例にある関連ドキュメント。

8
metakermit

ImageFieldは単なる文字列であり、MEDIA_ROOT設定に対する相対パスです。ファイルを保存し(PILを使用して画像であることを確認することもできます)、フィールドにファイル名を入力します。

したがって、コードとは異なり、urllib.urlopenの出力をファイル(メディアの場所内)に保存し、パスを計算し、モデルに保存する必要があります。

5
Oli

Python 3でこの方法で行います。これは、Python 2。小さい場合は、メモリにバッファリングする代わりに、ファイルに応答を書き込むことをお勧めします。

Djangoはファイルオブジェクトでseek()を呼び出し、urlopen応答はシークをサポートしないため、代わりにread()によって返されたバイトオブジェクトを渡すことができます。

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
jbg