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

82 python django urllib django-models

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

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

class Photo(models.Model):
    image = models.ImageField('Label', upload_to='path/')
Run Code Online (Sandbox Code Playgroud)

我想从图像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)
Run Code Online (Sandbox Code Playgroud)

如果不告诉我,我希望我已经很好地解释了这个问题.

谢谢 :)

编辑:

这可能有效,但我不知道如何转换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)
Run Code Online (Sandbox Code Playgroud)

Chr*_*ams 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))
Run Code Online (Sandbox Code Playgroud)

  • 不需要临时文件.你可以使用`requests`而不是`urllib2`:`image_content = ContentFile(requests.get(url_image).content)`然后`obj.my_image.save("foo.jpg",image_content)`. (25认同)
  • 最后一行在做什么?什么是'im`对象来自? (3认同)

pit*_*ess 31


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)


met*_*mit 9

结合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)
Run Code Online (Sandbox Code Playgroud)

Django的ContentFile文档Requests的文件下载示例中更相关的文档.


Oli*_*Oli 5

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

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


jbg*_*jbg 5

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

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


con*_*tmp 5

最近我在 python 3 和 Django 3 中使用了以下方法,也许这对其他人来说也可能很有趣。它类似于克里斯·亚当斯的解决方案,但对我来说它不再起作用了。

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()
Run Code Online (Sandbox Code Playgroud)