2014-10-26 129 views
1

我正在使用Django 1.7和Python 3.4。Django从ImageField下载图像

我有这样一个模型:

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

现在我要下载的文件保存在/静态/ 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?) 

下一步是什么?如何创建一个强制下载该图像的视图?

回答

3

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

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在第二TO-获取文件名最后一行...filename=%s" % img.name您应该编辑代码以适合您的项目。

  2. 有在ImageField的现场file,在代码在这里我使用img.file获得文件的路径,你应该改变,对img.YOUR_IMAGE_FIELD.file或任何你需要获得路径图像

+0

请注意,如果名称在ASCII范围内,但使用宽字符失败时会失败。 Content-Disposition支持UTF-8编码名称,但旧版浏览器(IE8之前)将完全忽略它。在内部,它更好地隐藏重定向到URL中具有文件名的URL。所有的浏览器都会支持这一点,你将避免IE浏览器附加的错误[1]错误,以避免出现文件名错误 – 2014-10-26 20:49:23

+0

@MikeMcMahon我不完全确定你想要解释什么,但我很乐意学习任何其他方式来做到这一点,如果它更好。你能给一些关于这方面的信息的链接吗? – AlvaroAV 2014-10-26 20:51:02

+0

考虑使用汉字字符或西里尔文字符的文件名。 'filename =%s'将不起作用。它可以在FireFox/Chrome中使用,但不能在IE8以及可能的移动浏览器上使用(取决于使用哪种移动设备和浏览器技术)。有一个'filename * = UTF-8''%s'格式,它支持UTF-8编码的字符,这有时会*有效*。最好(从DJango内部)执行HttpRedirect()到包含完整文件名的URL作为路径的一部分。所有的浏览器都可以解释这个和标准范围之外的字符。 – 2014-10-26 20:54:32

0

您需要使用Content-Disposition头,看看这里:

Generating file to download with Django
Django Serving a Download File

+1

虽然此链接可能回答此问题,但最好在此处包含答案的重要部分并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 – 2014-10-26 21:50:42

+0

注意到,经验教训:) – 2014-10-27 14:06:41

0

其他两个答案都可以,但是由于性能方面的原因,不推荐使用Django提供静态文件的许多地方进行广告宣传。最好使用你的web服务器(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的视图。

+0

这将打开webbrowser中的图像,我想要的是强制将此图像下载到用户下载文件夹;)。 – 2014-10-26 21:20:02

+0

我编辑答案添加http://www.w3schools.com/tags/att_a_download.asp – dukebody 2014-10-26 22:33:10

-1

这里是包含任何字符类型

# 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) 
+0

不幸的是它是行不通的。请参阅下面的答案。 – 2014-10-26 21:55:21

+0

我从我用于我们的文件分发系统的源代码中提取这个。什么没有用? – 2014-10-26 22:05:51

+0

@SzymonBarylak什么不适合你? – 2014-10-27 00:39:50

-1

它不工作的文件你跨浏览器的安全下载。我做了这样的事情:

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图像查看器seys'不是JPEG文件。用0x89上为0x50' 开始

+0

ANY JPEG文件的前两个字节应分别为0xFF和0xE0。上传或下载时,您是否在任何时候不将图像视为二进制文件?任何影响内容的操作都应该分别以'rb'或'wb'模式打开文件。 – 2014-10-27 21:36:37

0

这方面的一个类为本次型exampe会是这样(我使用python魔法才能得到正确的内容类型的文件):

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.2