【问题标题】:Django download image from ImageFieldDjango 从 ImageField 下载图像
【发布时间】:2014-10-26 20:27:04
【问题描述】:

我正在使用 Django 1.7 和 Python 3.4。

我有一个这样的模型:

class ImageModel(models.Model):
    image = models.ImageField(verbose_name='image', upload_to='uploaded_images/')

现在我想下载保存在 /static/uploaded_images/ 中的图像。 例如我有一个这样的链接:www.example.com/image/download/1,其中 1 是 ImageModel 对象的 id。

现在我有一个看法:

def download_image(request, image_id):
     img = ImageModel.objects.get(id=image_id)
     ( what I need to do? )

接下来呢?如何创建将强制下载该图像的视图?

【问题讨论】:

    标签: python django


    【解决方案1】:

    你可以试试这段代码,也许需要一些注意事项:

    from django.core.servers.basehttp import FileWrapper
    import mimetypes
    
    def download_image(request, image_id):
        img = ImageModel.objects.get(id=image_id)
        wrapper      = FileWrapper(open(img.file))  # img.file returns full path to the image
        content_type = mimetypes.guess_type(filename)[0]  # Use mimetypes to get file type
        response     = HttpResponse(wrapper,content_type=content_type)  
        response['Content-Length']      = os.path.getsize(img.file)    
        response['Content-Disposition'] = "attachment; filename=%s" %  img.name
        return response
    
    1. 我假设您的ImageModel 中有一个字段.name 以获取倒数第二行...filename=%s" % img.name 中的文件名您应该编辑代码以适合您的项目。

    2. ImageField中有一个字段是file,这里的代码我使用img.file来获取文件的路径,您应该将其更改为 img.YOUR_IMAGE_FIELD.file 或获取图像路径所需的任何内容

    【讨论】:

    • 请注意,当名称在 ASCII 范围内时,这将正常工作,但在使用宽字符时会惨遭失败。 Content-Disposition 支持 UTF-8 编码的名称,但较旧的浏览器(IE8 之前)将完全忽略这一点。在内部,使用 URL 中的文件名隐藏重定向到 URL 效果更好。所有浏览器都将支持这一点,您将避免 IE 将附加到被破坏的文件名的讨厌的 [1] 错误
    • @MikeMcMahon 我不完全确定您要解释什么,但如果有更好的方法,我很乐意学习任何其他方法。您能否提供一些相关信息的链接?
    • 考虑使用汉字字符或西里尔字符的文件名。 filename=%s 将不起作用。它将在 FireFox / Chrome 中运行,但不适用于 filename*=UTF-8''%s 格式支持 UTF-8 编码字符,这有时会起作用。最好(从 DJango 内部)对包含完整文件名作为路径一部分的 URL 执行 HttpRedirect()。所有浏览器都可以解释这个和标准范围之外的字符。
    • 啊,现在我明白了,我一直在我的项目中使用 unicode 字符,从来没有遇到过这个问题,谢谢你的信息!我也对您用于将文件发送给用户的不同方式感兴趣
    【解决方案2】:

    你需要使用Content-Disposition header,看这里:

    Generating file to download with Django
    Django Serving a Download File

    【讨论】:

      【解决方案3】:

      基于类的视图类型示例是这样的(我正在使用 python-magic 来获取文件的正确内容类型):

      import os
      import magic
      
      from django.views.generic import View
      from django.http import HttpResponse
      
      from .models import ImageModel
      
      
      class ImageDownloadView(View):
      
          def get(self, request, *args, **kwargs):
              image = ImageModel.objects.get(pk=self.kwargs['image_id'])
              image_buffer = open(image.file.path, "rb").read()
              content_type = magic.from_buffer(image_buffer, mime=True)
              response = HttpResponse(image_buffer, content_type=content_type);
              response['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(image.file.path)
              return response
      

      这适用于 Django 1.10.7,但对于 Django 1.7 应该没有那么不同

      【讨论】:

        【解决方案4】:

        其他两个答案都可以,但是出于性能原因,不建议使用 Django 来提供静态文件,但正如许多地方所宣传的那样。最好使用您的网络服务器(nginx/apache...)来提供它。

        您不需要额外的视图来提供静态文件。只需在模板中呈现指向文件的链接:

        <a href="{{object.image.url}} download">Download this image!</a>
        

        其中objectImageModel 的一个实例。

        django.db.models.fields.files.FieldFile.url

        如果你真的想在像www.example.com/image/download/1 这样的 URL 中有一个视图,你可以简单地编写一个重定向到从该字段获得的图像 URL 的视图。

        【讨论】:

        • 这将在 webbrowser 中打开图像,我想要实现的是强制将此图像下载到用户下载文件夹中;)。
        【解决方案5】:

        这是包含任何字符类型的文件的跨浏览器安全下载

        # Even better as it works in any browser (mobile and desktop)
        def safe_name(file_name):
            """
            Generates a safe file name, even those containing characters like ? and &
            And your Kanji and Cyrillics are supported! 
            """
            u_file_name = file_name.encode('utf-8')
            s_file_name = re.sub('[\x00-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), u_file_name)
            return s_file_name
        
        # Handled by url(r'^/image/download/(\d+)/.+$
        def safe_download_image(request, image_id):
            """ 
            Safely downloads the file because the filename is part of the URL
            """
            img = ImageModel.objects.get(id=image_id)
            wrapper      = FileWrapper(open(img.file))  # img.file returns full path to the image
            content_type = mimetypes.guess_type(filename)[0]  # Use mimetypes to get file type
            response     = HttpResponse(wrapper,content_type=content_type)  
            response['Content-Length']      = os.path.getsize(img.file)     
            # This works for most browsers, but IE will complain sometimes
            response['Content-Disposition'] = "attachment;"
            return response
        
        def download_image(request, image_id):
            img = ImageModel.objects.get(id=image_id)
            redirect_do = safe_name(img.name)
            return HttpResponseRedirect('/image/download/' + img_id + '/' + redirect_to)
        

        【讨论】:

        • 不幸的是它不起作用。请参阅下面的答案。
        • 我从我用于文件分发系统的源代码中提取了这个。什么不起作用?
        • 我在下面添加了它,作为我问题的答案。
        【解决方案6】:

        这是行不通的。我做了这样的事情:

        wrapper = FileWrapper(img.file)  # img.file returns full path to the image
        content_type = mimetypes.guess_type(str(img.file))[0]  # Use mimetypes to get file type
        response = HttpResponse(wrapper, content_type=content_type)
        response['Content-Length'] = os.path.getsize(str(img.file))
        response['Content-Disposition'] = "attachment; filename=%s" % img.name
        

        img 指向我的ImageField 字段。文件已下载,但我无法打开它。 xUbuntu 图像查看器显示“不是 JPEG 文件。以 0x89 0x50' 开头

        【讨论】:

        • 任何 JPEG 文件的前两个字节应分别为 0xFF0xE0。您在上传或下载时是否在任何时候都不将图像视为二进制文件?任何影响内容的操作都应分别以“rb”或“wb”模式打开文件。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-22
        • 2011-03-27
        • 2019-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多