【问题标题】:Download a remote image and save it to a Django model下载远程图像并将其保存到 Django 模型
【发布时间】:2013-04-16 22:38:40
【问题描述】:

我正在编写一个 Django 应用程序,它将获取特定 URL 的所有图像并将它们保存在数据库中。

但我不知道如何在 Django 中使用 ImageField。

Settings.py

MEDIA_ROOT = os.path.join(PWD, "../downloads/")

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://example.com/media/", "htp://media.example.com/"
MEDIA_URL = '/downloads/'

models.py

class images_data(models.Model):
        image_id =models.IntegerField()
        source_id = models.IntegerField()
        image=models.ImageField(upload_to='images',null=True, blank=True)
        text_ind=models.NullBooleanField()
        prob=models.FloatField()

download_img.py

def spider(site):
        PWD = os.path.dirname(os.path.realpath(__file__ ))
        #site="http://en.wikipedia.org/wiki/Pune"
        hdr= {'User-Agent': 'Mozilla/5.0'}
        outfolder=os.path.join(PWD, "../downloads")
        #outfolder="/home/mayank/Desktop/dreamport/downloads"
        print "MAYANK:"+outfolder
        req = urllib2.Request(site,headers=hdr)
        page = urllib2.urlopen(req)
        soup =bs(page)
        tag_image=soup.findAll("img")
        count=1;
        for image in tag_image:
                print "Image: %(src)s" % image
                filename = image["src"].split("/")[-1]
                outpath = os.path.join(outfolder, filename)
                urlretrieve('http:'+image["src"], outpath)
                im = img(image_id=count,source_id=1,image=outpath,text_ind=None,prob=0)
                im.save()
                count=count+1

我在一个视图中调用 download_imgs.py,例如

        if form.is_valid():
                url = form.cleaned_data['url']
                spider(url)

【问题讨论】:

  • 您要将图像保存为数据库中的 blob 还是图像路径
  • @mossplix - 无论哪种方式......但是如果我将图像保存为路径,那么我也希望在我的服务器上使用图像
  • @PauloBu - 我多次阅读该文件。但不知道如何继续
  • 你是如何获取图片的?

标签: python django django-models


【解决方案1】:

Django Documentation 始终是开始的好地方

class ModelWithImage(models.Model):
    image = models.ImageField(
        upload_to='images',
    )

更新

所以这个脚本有效。

  • 循环下载图片
  • 下载图片
  • 保存到临时文件
  • 应用于模型
  • 保存模型

.

import requests
import tempfile

from django.core import files

# List of images to download
image_urls = [
    'http://i.thegrindstone.com/wp-content/uploads/2013/01/how-to-get-awesome-back.jpg',
]

for image_url in image_urls:
    # Stream the image from the url
    response = requests.get(image_url, stream=True)

    # Was the request OK?
    if response.status_code != requests.codes.ok:
        # Nope, error handling, skip file etc etc etc
        continue
    
    # Get the filename from the url, used for saving later
    file_name = image_url.split('/')[-1]
    
    # Create a temporary file
    lf = tempfile.NamedTemporaryFile()

    # Read the streamed image in sections
    for block in response.iter_content(1024 * 8):
        
        # If no more file then stop
        if not block:
            break

        # Write image block to temporary file
        lf.write(block)

    # Create the model you want to save the image to
    image = Image()

    # Save the temporary image to the model#
    # This saves the model so be sure that it is valid
    image.image.save(file_name, files.File(lf))

一些参考链接:

  1. requests - “HTTP for Humans”,我更喜欢这个而不是 urllib2
  2. tempfile - 保存临时文件而不是磁盘
  3. Django 文件字段save

【讨论】:

  • 我这样做了,甚至相应地更改了 MEDIA_ROOT 路径.. 现在呢?
  • 好的,将图像放入数据库或之后访问它的问题是什么?
  • 无法通过我的服务器上的图像将图像发送到数据库
  • 向我们展示更多代码。您尝试获取图像的viewmodel 定义,可能还有settings.py
  • 我知道这不是一个可接受的评论,但这对我有很大帮助!谢谢你,@rockingskier
【解决方案2】:

如果您想保存下载的图像而不先将它们保存到磁盘(不使用NamedTemporaryFile 等),那么有一种简单的方法可以做到这一点。

这将比下载文件并将其写入磁盘稍微快一些,因为这一切都在内存中完成。请注意,此示例是为 Python 3 编写的 - 该过程与 Python 2 中的过程相似,但略有不同。

from django.core import files
from io import BytesIO
import requests

url = "https://example.com/image.jpg"
resp = requests.get(url)
if resp.status_code != requests.codes.ok:
    #  Error handling here

fp = BytesIO()
fp.write(resp.content)
file_name = url.split("/")[-1]  # There's probably a better way of doing this but this is just a quick example
your_model.image_field.save(file_name, files.File(fp))

其中your_model 是您要保存到的模型的一个实例,.image_fieldImageField 的名称。

有关更多信息,请参阅io 的文档。

【讨论】:

    【解决方案3】:

    作为我认为您要问的一个例子:

    在 forms.py 中:

    imgfile = forms.ImageField(label = 'Choose your image', help_text = 'The image should be cool.')
    

    在 models.py 中:

    imgfile =   models.ImageField(upload_to='images/%m/%d')
    

    因此会有来自用户的 POST 请求(当用户完成表单时)。该请求将基本上包含一个数据字典。字典保存提交的文件。要将请求集中在来自字段(在我们的示例中为 ImageField)的文件上,您可以使用:

    request.FILES['imgfield']
    

    您将在构建模型对象时使用它(实例化您的模型类):

    newPic = ImageModel(imgfile = request.FILES['imgfile'])
    

    要以简单的方式保存它,您只需使用赋予对象的 save() 方法(因为 Django 太棒了):

    if form.is_valid():
        newPic = Pic(imgfile = request.FILES['imgfile'])
        newPic.save()
    

    默认情况下,您的图像将存储到您在 settings.py 中为 MEDIA_ROOT 指定的目录。

    访问模板中的图片:

    <img src="{{ MEDIA_URL }}{{ image.imgfile.name }}"></img>
    

    url 可能很棘手,但这里有一个简单的 url 模式的基本示例,用于调用存储的图像:

    urlpatterns += patterns('',
            url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
                'document_root': settings.MEDIA_ROOT,
            }),
       )
    

    希望对你有帮助。

    【讨论】:

    • 我不想在中间涉及表单,因为我没有要求用户输入图像。你能告诉我我粘贴的代码中有问题吗?
    • 你声称你不知道如何使用 ImageField,所以我指导你。您并没有真正具体说明您要做什么,而且您的代码含糊不清。如果您尝试以特殊方式保存图像,则必须修改 save()。
    • 抱歉 vauge 代码...我想要的是这个..我要求用户输入一个 url...我将提取此 url 的所有图像,然后我必须保存这些提取的 url以及 db 中的一些其他信息...
    【解决方案4】:

    与上面@boltsfrombluesky 的回答类似,您可以在 Python 3 中执行此操作,而无需像这样的任何外部依赖项:

    from os.path import basename
    import urllib.request
    from urllib.parse import urlparse
    import tempfile
    
    from django.core.files.base import File
    
    def handle_upload_url_file(url, obj):
        img_temp = tempfile.NamedTemporaryFile(delete=True)
        req = urllib.request.Request(
            url, data=None,
            headers={
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
            }
        )
        with urllib.request.urlopen(req) as response:
            img_temp.write(response.read())
        img_temp.flush()
        filename = basename(urlparse(url).path)
        result = obj.image.save(filename, File(img_temp))
        img_temp.close()
        return result
    

    【讨论】:

      【解决方案5】:

      尝试这样做,而不是为图像分配路径...

          import urllib2
          from django.core.files.temp import NamedTemporaryFile
          def handle_upload_url_file(url):
              img_temp = NamedTemporaryFile()
              opener = urllib2.build_opener()
              opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:15.0) Gecko/20120427 Firefox/15.0a1')]
              img_temp.write(opener.open(url).read())
              img_temp.flush()
              return img_temp
      

      像这样使用上面的函数..

          new_image = images_data()
          #rest of the data in new_image and then do this.
          new_image.image.save(slug_filename,File(handle_upload_url_file(url)))
          #here slug_filename is just filename that you want to save the file with.
      

      【讨论】:

        【解决方案6】:

        如果您通过覆盖模型的保存方法来修改文件名并在 django 中遇到随机无效文件名(如我)来保存图像。您可以跟进以下代码(从已接受的答案复制):

        lf = tempfile.NamedTemporaryFile()
        
        
        for block in response.iter_content(1024*8):
        
                if not block:
                    break
        
                lf.write(block)
            lf.name = name.  # Set your custom file name here
            dc = ImageFile(file=files.File(lf))
        
            dc.file.save()
        

        我已经使用 django-storages 配置了我的存储,以便将媒体内容直接上传到 s3。由于某些原因,我无法替换文件名。经过一些研发,它奏效了。

        注意:我在模型中使用了 FileField,因此不需要几行代码

        【讨论】:

          【解决方案7】:
          # this is my solution
          from django.core import files
          from django.core.files.base import ContentFile
          
          import requests
          from .models import MyModel
          
          def download_img():
              r = requests.get("remote_file_url", allow_redirects=True)
              filename = "remote_file_url".split("/")[-1]
          
              my_model = MyModel(
                  file=files.File(ContentFile(r.content), filename)
              )
              my_model.save()
          
              return
          

          【讨论】:

          • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。
          【解决方案8】:
          def qrcodesave(request): 
              import urllib2;   
              url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0"; 
              opener = urllib2.urlopen(url);  
              mimetype = "application/octet-stream"
              response = HttpResponse(opener.read(), mimetype=mimetype)
              response["Content-Disposition"]= "attachment; filename=aktel.png"
              return response 
          

          【讨论】:

          • 您所做的是描述如何强制用户的浏览器下载图像。 OP 想将图像保存到他的数据库中的ImageField
          猜你喜欢
          • 1970-01-01
          • 2023-03-04
          • 1970-01-01
          • 1970-01-01
          • 2011-11-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-03-23
          相关资源
          最近更新 更多