93

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

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

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

9 に答える 9

98

この同じ問題に対して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))
于 2010-01-26T18:59:14.870 に答える
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)

于 2009-09-08T10:54:40.170 に答える
6

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

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

于 2009-09-08T10:35:58.347 に答える
5

Python 3 ではこの方法で行いますが、これは Python 2 での単純な適応で動作するはずです。これは、取得するファイルが小さいという私の知識に基づいています。そうでない場合は、メモリにバッファリングするのではなく、応答をファイルに書き出すことをお勧めします。

Django はファイル オブジェクトで seek() を呼び出し、urlopen 応答はシークをサポートしていないため、BytesIO が必要です。代わりに、read() によって返されたバイト オブジェクトを 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))
于 2014-10-13T00:40:01.900 に答える
3

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

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.title = 'Foo bar'
new_image.file = SimpleUploadedFile(basename, open(tmpfile, "rb").read())
new_image.save()
于 2020-04-04T22:16:45.457 に答える
0

質問からほぼ11年が経過し、最も評判の良い回答が投稿されました。@chris-adams に感謝します。更新されたパッケージとサポートとともに同じ回答を再投稿しています。

#! /usr/bin/python3
# lib/utils.py

import urllib3                                          # http Request Package.
from typing import Optional

from django.core.files import File                      # Handle Files in Django
from django.core.files.temp import NamedTemporaryFile   # handling temporary files.


def fetch_image(url: str, instance: models.Model, field: str, name: Optional[str]=None):
    """
    fetch_image Fetches an image URL and adds it to the model field.
    the parameter instance does not need to be a saved instance. 

    :url: str = A valid image URL.
    :instance: django.db.models.Model = Expecting a model with image field or file field. 
    :field: str = image / file field name as string; 
    [name:str] = Preferred file name, such as product slug or something.  

    :return: updated instance as django.db.models.Model, status of updation as bool.
    
    """
    
    conn = urllib3.PoolManager()
    response = conn.request('GET', url)
    if response.status <> 200:
        print("[X] 404! IMAGE NOT FOUND")
        print(f"TraceBack: {url}")
        return instance, False
    
    file_obj = NamedTemporaryFile(delete=True)
    file_obj.write( response.data )
    file_obj.flush()

    img_format = url.split('.')[-1]
    
    if name is None:
        name = url.split('/')[-1]
    
    if not name.endswith(img_format):
        name += f'.{img_format}'
    
    django_file_obj = File(file_obj)
    (getattr(instance, field)).save(name, django_file_obj)
    return instance, True
    

Python 3.7.5 で Django==2.2.12 でテスト済み


if __name__ == '__main__':
    instance = ProductImage()
    url = "https://www.publicdomainpictures.net/pictures/320000/velka/background-image.png"
    instance, saved = fetch_image(url, instance, field='banner_image', name='intented-image-slug')
    status = ["FAILED! ", "SUCCESS! "][saved]
    print(status, instance.banner_image and instance.banner_image.path)
    instance.delete()

于 2021-08-17T08:52:56.790 に答える
-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()
于 2012-10-28T03:49:13.240 に答える