Django 从 ImageField 下载图片

3 投票
7 回答
12931 浏览
提问于 2025-04-29 19:16

我正在使用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? )

接下来该怎么做?如何创建一个视图来强制下载那张图片呢?

暂无标签

7 个回答

0

这段代码在新版本的Django中运行得很好:

import mimetypes

def download_image(request, id):
    img = ImageModel.objects.get(id=id)
    wrapper = img.field_name
    content_type = mimetypes.guess_type(img.field_name.name)[0]
    response = HttpResponse(wrapper, content_type=content_type)
    response['Content-Length'] = img.field_name.size
    response['Content-Disposition'] = f"attachment; filename={img.field_name.name}"
    return response

把field_name换成你自己的字段名。这个字段必须是ImageField(图片字段)或者FileField(文件字段)。

0

其他两个回答都不错,但很多地方都提到,使用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。

1

一个基于类视图的例子可以是这样的(我使用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中应该也差不多。

1

你需要使用 Content-Disposition 这个头部信息,看看这里:

用Django生成可下载的文件
Django提供下载文件

4

你可以试试这个代码,不过可能需要注意一些细节:

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,或者根据你的需要来获取图片的路径。

撰写回答