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)

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

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

編集:

これはうまくいくかもしれませんがcontent、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)

回答:


96

この同じ問題のためにhttp://www.djangosnippets.org/snippets/1890/を作成しました。urllib.urlretrieveはデフォルトでエラー処理を実行しないため、コードは上記のpithylessの回答に似ています。したがって、必要なものではなく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 2014年

1
@priestc:imは少し簡潔でした-その例でimは、モデルインスタンスでありfile、そのインスタンスのFileField / ImageFieldの想像を絶する名前でした。ここでの実際のAPIドキュメントは重要です。この手法は、Django Fileオブジェクトがオブジェクトにバインドされている場所であればどこでも機能するはずです:docs.djangoproject.com/en/1.5/ref/files/file/…–
Chris Adams

26
一時ファイルは不要です。使用するrequests代わりにurllib2:あなたが行うことができimage_content = ContentFile(requests.get(url_image).content)、その後とobj.my_image.save("foo.jpg", image_content)
スタン

スタン:リクエストはそれを単純化しますが、エラーや不完全な応答との混同を避けるために最初にraise_for_status()を呼び出さない限り、ワンライナーが問題になるというIIRC
Chris Adams

もともとはDjango1.1 / 1.2時代に書かれていたので、これを最新化することはおそらく良い考えでしょう。そうは言っても、ContentFileにはファイル全体をメモリにロードするという問題がまだあるので、適切なチャンクサイズでiter_contentを使用するのが最適です。
クリスアダムス

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)


こんにちは、私を助けてくれてありがとう;)。問題は(私はドキュメントを引用します):「content引数はFileのインスタンスまたはFileのサブクラスでなければならないことに注意してください。」では、コンテンツを使用してファイルインスタンスを作成するためのソリューションはありますか?

新しい編集を確認してください。これは実際の例になるはずです(私はテストしていませんが)
pithyless 2009

他のフィールドもある私のモデルはどうですか。URLなどのように。idの場合はmodel.image.save(...)を実行します。他のフィールドを保存するにはどうすればよいですか?それらはnullにすることはできません編集:それはこのようなものでしょうか?>>> car.photo.save( 'myphoto.jpg'、contents、save = False)>>> car.save()
ハリー

self.url ?? ...ここのself.urlとは??
DeadDjangoDjoker 2015年

@DeadDjangoDjokerわかりません、私の答えを編集した人に尋ねる必要があります。この回答はこの時点で5歳です。私は後世のために以前の「実用的な」解決策に戻りましたが、正直なところ、あなたはクリス・アダムの答えを持っている方が良いです。
pithyless 2015年

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

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

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


5

私はPython3でこのようにしています。これは、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))

File(io)は<File:None>を返します
Susaj SNair19年

@SusajSNairこれは、ファイルに名前がなく、__repr__メソッドFileが名前を書き込むためです。必要にname応じて、Fileオブジェクトを作成した後にオブジェクトに属性を設定できますFile(io)が、私の経験では、それは重要ではありません(印刷すると見栄えが良くなることを除けば)。ymmv。
JBG

3

最近、私はpython3とDjango3内で次のアプローチを使用しています。これは、他の人にとっても興味深いかもしれません。これはChrisAdamsのソリューションに似ていますが、私にとってはもう機能しませんでした。

# -*- 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 + Django2)。URLによっては、basenameの拡張子が正しいとは限らないというのは、少し些細なコメントです。
physicsAI


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