Django:从图像url在ImageField中添加图像

时间:2009-09-08 10:29:44

标签: python django urllib django-models

请原谅我丑陋的英语; - )

想象一下这个非常简单的模型:

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

我想从图片网址创建一张照片(也就是说,不是在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)

8 个答案:

答案 0 :(得分:95)

我刚刚为同样的问题创建了http://www.djangosnippets.org/snippets/1890/。代码类似于上面的pithyless'回答,除了它使用urllib2.urlopen,因为默认情况下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))

答案 1 :(得分:30)


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)

答案 2 :(得分:7)

结合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's ContentFile documentationRequests' file download示例中的更多相关文档。

答案 3 :(得分:5)

ImageField只是一个字符串,是相对于MEDIA_ROOT设置的路径。只需保存文件(您可能希望使用PIL检查它是否为图像)并使用其文件名填充该字段。

因此,它与您的代码的不同之处在于,您需要将urllib.urlopen的输出保存到文件(在媒体位置内),计算路径,将其保存到模型中。

答案 4 :(得分:4)

我在Python 3上这样做,它应该适用于Python 2上的简单修改。这是基于我的知识,我正在检索的文件很小。如果不是,我可能会建议将响应写入文件,而不是在内存中缓冲。

需要BytesIO,因为Django在文件对象上调用seek(),而urlopen响应不支持搜索。您可以将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))

答案 5 :(得分: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()

答案 6 :(得分:2)

刚刚发现您不必生成临时文件:

Stream url content directly from django to minio

我必须将文件存储在minio中,并且要有没有太多磁盘空间的django docker容器,并且需要下载大的视频文件,所以这对我真的很有帮助。

答案 7 :(得分:-3)

这是正确和有效的方式

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