Django下载文件无法正常工作。

3
我正在尝试编写一个脚本,用于在用户的计算机上下载上传的文件。问题在于下载根本不起作用(它要么向我下载一个空文件,要么给我一些错误)。
最后一个错误是:强制转换为Unicode:需要字符串或缓冲区,但发现了FieldFile。
def download_course(request, id):
    course = Courses.objects.get(pk = id).course

    path_to_file = 'root/cFolder'
    filename = course # Select your file here.                                
    wrapper = FileWrapper(file(course))
    content_type = mimetypes.guess_type(filename)[0]
    response = HttpResponse(wrapper, content_type = content_type)
    response['Content-Length'] = os.path.getsize(filename)
    response['Content-Disposition'] = 'attachment; filename=%s/' % smart_str(course)

    return response

如何正确声明文件名,以便每次下载时知道要下载哪个文件: 实际上,文件名是如上所述的“course”。 谢谢!
2个回答

5

编辑

我认为您需要从FileField对象中提取path值:

def download_course(request, id):
    course = Courses.objects.get(pk = id).course

    path = course.path # Get file path
    wrapper = FileWrapper( open( path, "r" ) )
    content_type = mimetypes.guess_type( path )[0]

    response = HttpResponse(wrapper, content_type = content_type)
    response['Content-Length'] = os.path.getsize( path ) # not FileField instance
    response['Content-Disposition'] = 'attachment; filename=%s/' % \ 
                                       smart_str( os.path.basename( path ) ) # same here

    return response

为什么会这样呢:

假设我有一个模型(实际上我确实有这个模型):

class DanePracodawcy( DaneAdresowe, DaneKontaktowe ):
    # other fields
    logo = ImageWithThumbnailsField( upload_to = 'upload/logos/',
                                  thumbnail = {'size': (180, 90)},
                                  blank = True )

ImageWithThumbnailsField 是 FileField 的子类,因此其行为与 FileField 相同。现在,在执行 SELECT 时:

mysql> select logo from accounts_danepracodawcy;
+-----------------------------+
| logo                        |
+-----------------------------+
| upload/logos/Lighthouse.jpg |
+-----------------------------+
1 row in set (0.00 sec)

它显示(相对于MEDIA_ROOT)存储文件的路径。但是当我访问logo模型属性时:

[D:projekty/pracus]|1> from accounts.models import DanePracodawcy
[D:projekty/pracus]|4> DanePracodawcy.objects.get().logo
                   <4> <ImageWithThumbnailsFieldFile: upload/logos/Lighthouse.jpg>
[D:projekty/pracus]|5> type( _ )
                   <5> <class 'sorl.thumbnail.fields.ImageWithThumbnailsFieldFile'>

我得到了某个对象的实例。如果我尝试将该实例传递给 os.path.getsize

[D:projekty/pracus]|8> import os.path
[D:projekty/pracus]|9> os.path.getsize( DanePracodawcy.objects.get().logo )
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

D:\projekty\pracus\<ipython console> in <module>()

C:\Python26\lib\genericpath.pyc in getsize(filename)
     47 def getsize(filename):
     48     """Return the size of a file, reported by os.stat()."""
---> 49     return os.stat(filename).st_size
     50
     51

TypeError: coercing to Unicode: need string or buffer, ImageWithThumbnailsFieldFile found

我也遇到了TypeError的问题,所以我需要将文件路径作为字符串获取,可以通过path属性实现:

[D:projekty/pracus]|13> os.path.getsize(  DanePracodawcy.objects.get().logo.path )
                   <13> 561276L

或者,我可以获取name属性,并将其与MEDIA_ROOT设置一起使用os.path.join

[D:projekty/pracus]|11> from django.conf import settings
[D:projekty/pracus]|12> os.path.getsize(  os.path.join( settings.MEDIA_ROOT, DanePracodawcy.objects.get().logo.name ) )
                   <12> 561276L

但这是不必要的打字。

最后需要注意的是:因为path是绝对路径,我需要提取文件名并将其传递给Content-Disposition头:

[D:projekty/pracus]|16> DanePracodawcy.objects.get().logo.path
                   <16> u'd:\\projekty\\pracus\\site_media\\upload\\logos\\lighthouse.jpg'
[D:projekty/pracus]|17> os.path.basename( DanePracodawcy.objects.get().logo.path )
                   <17> u'lighthouse.jpg'

nop,课程名称是表中“course”字段的对应项。 - dana
嗯...这很奇怪,因为我的错误仍然是强制转换为Unicode:需要字符串或缓冲区,但找到了FieldFile。我真的不明白为什么。 - dana
1
抱歉,我的答案是错误的,我重新检查并进行了编辑。现在上面的代码应该按预期工作,并且我尝试解释为什么它会这样工作。 - cji
它完美地运行了!!只是您忘记声明filename = course.name。我已经接受了答案。您能否在此处也发布您的答案链接:http://stackoverflow.com/questions/3141682/django-download-file-empty(我已经设置了奖励,并希望在那里接受您的答案。谢谢!) - dana
我最后进行了一次编辑,以更正未声明的文件名(我将该变量命名为“path”,因为我认为在这个代码中这样更合适)。很高兴能帮上忙 :) - cji

2

除非您正在让用户下载动态生成的文件,否则我不明白为什么您需要做所有这些操作。

您可以让此视图重定向到适当的路径,静态文件由提供服务的服务器(通常是apache或nginx)设置相应的标头。

我会将您的这个视图写成如下形式:

from django.conf import settings

def download_course(request,id):
    course = get_object_or_404(Course,id=id)
    filename = course.course
    return redirect('%s/%s'%(settings.MEDIA_URL,filename))

祝您愉快 :)


现在它说:“FieldFile”对象没有属性“_default_manager”。 - dana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接