Web2py:下载文件/显示图像

时间:2012-09-22 02:31:01

标签: python image file download web2py

我最近跳进了Web2py框架,我觉得非常好。但是,我现在遇到了“基本”问题。

上下文

我正在建立的网站是科学代码的界面:人们填写表格并提交。然后,代码处理数据(写在共享文件夹内的文件中),在后台作为守护进程运行(代码没有与网站的链接,除了此共享文件夹和{{1}之间的JSONRPC链接})。 代码生成我希望网站用户可以使用的文件和图像(即将它们返回给他们要求的结果)。 作业完成后,代码会使用JSONRPC服务链接将结果“推送”到网站,该链接完美运行。结果位于具有生成名称的文件夹中,该文件夹基本上具有以下结构:

code->website

当前实施(无法正常工作)

目前我有3个数据库:

unique_folder_name/
        file1.txt
        file2.csv
        file3.xls
        image1.png
        image2.png

当代码“推送”结果时,Web2py中的某些模块会在“结果”数据库中创建条目,并在“文件”数据库中创建与作业关联的条目。 由于我没有找到一种方法来使文件(已经在文件系统上)可用于Web2py而不将其复制到上传文件夹,我当前存储这样的文件(在模块中):

# Job database
db.define_table("job",
    Field('owner', 'string', length=60, required=True, writable=True, readable=True),
    Field('uniq_id', "string", length=60, required=True, unique=True, writable=False, readable=True))

# Result database
db.define_table("result",
    Field("job", "reference job"),
    Field("x", "integer", default=1),
    Field("y", "integer", default=0),
    Field("z", "integer", default=0),
    Field("data", "string", length=500),
    Field("message", "string", length=200))

# File database
db.define_table("file",
    Field("job", "reference job"),
    Field("file", "upload"),
    Field("isimage", "boolean", default=False))

然后,当我想用​​图像创建视图时,我(在一个模块中):

stream = open(os.path.join(directory, _file), 'rb')
current.db.file.insert(job=jid, file=current.db.file.file.store(stream, _file), isimage=isimg)

并在视图中:`{{= div}}``

问题

这只是不起作用......显示页面的源代码如下:

rows = current.db((current.db.file.job==jid) & (current.db.file.isimage==True)).select()
for row in rows:
    div.append(I(_src=URL(c="default", f="download", args=os.path.join(directory, row.file)), _width="500", _height="500"))

如果我在地址栏中输入此URL,则文件正确下载,否则图像不会显示在网页上。 此外,我必须给出文件的路径,即使Web2py确实将文件复制到'upload'文件夹(带有新的安全丑陋名称:)),否则链接无法正常工作。 所以:没有显示图像,加上文件被复制到'upload'文件夹中:(

我迷路了,不知道如何解决这个问题。 (我还尝试在构建图像URL时添加请求对象,并尝试了自定义下载功能......到目前为止还没有工作)。

编辑(解决方案)

嗯,我的代码中有一个明显的错误,我错过了:图片标记帮助器不是<i height="500" src="/mycode/default/download//path/to/directory/file.file.9b7d3a0367de0843.6d732d72732e706e67.png" width="500"></i> ,而是I :)与{{1}混淆引起的简单错误在twitter bootstrap中用于图标的标签...这样就解决了显示问题。 对于流媒体文件而不在上传文件夹中复制它们(即不使用数据库中的IMG字段), rochacbruno (非常感谢他)让我走上正轨。请参阅我自己的答案以获得完整的解决方案。

3 个答案:

答案 0 :(得分:2)

您必须创建自己的下载功能

import os
def my_download():
    base_path = request.args(0) # /path
    subdirectory = request.args(1) # directory
    filename = request.args(2)
    fullpath = os.path.join(request.folder, base_path, subdirectory, filename)
    response.stream(os.path.join(request.folder, fullpath))

默认/下载旨在与db和默认存储方式一起使用。

答案 1 :(得分:2)

所以这是我问题的完整解决方案。

db.py文件中,我已按此定义替换了'file'表(因此文件保留原样,不会复制到web2py上传文件夹中):

# File database
db.define_table("file",
    Field("job", "reference job"),
    Field("name", "string", length=30, required=True),   # stores the filename (without path)
    Field("isimage", "boolean", default=False))

然后,在一个控制器(例如'mycontroller')中,我已经定义了这个函数来传输文件:

from mymodule import OUTPUT  # this is the base directory of the files
from gluon.contenttype import contenttype

def export():
    # allow to download files
    jid = request.args(0)
    fid = request.args(1)

    if None in (jid, fid):
        res = 'Invalid URL'
    else:
        # get the file row
        row = db.file(fid)

        # some checks (not necessary if you know what you're doing)
        jrow = db.job(jid)
        if row is None:
            res = "unknown file ID"
        elif jrow.id  is None:
            res = "unknown job ID"
        else:
            filename = row.name
            # jrow.perma_id, is a field in the 'job' DB, that I use to create a unique
            # directory name, so the files of job ID 'jid' are under: OUTPUT/perma_id/
            fullname = os.path.join(OUTPUT, jrow.perma_id, filename)

            ext = os.path.splitext(filename)[1]
            response.headers['Content-Type'] = contenttype(ext)
            response.headers['Content-disposition'] = 'attachment; filename=%s' % filename
            res = response.stream(open(fullname, "rb"), chunk_size=4096)

    return res

请注意,此时我遇到了另一个问题:我首先想到将完整路径作为请求参数传递(例如。URL(c='mycontroller', f='export', args=(path, filename))), 但它没有用,因为path包含'/'被分成多个参数...... 如果您没有像我这样的简单路径(即只更改一个组件),您可以将路径存储到“文件”DB中。

然后,对于视图(使用模块或任何你喜欢的):

rows = current.db((current.db.file.job==jid) & (current.db.file.isimage==True)).select()
for row in rows:
    div.append(IMG(_src=URL(c="mycontroller", f="export", args=(jid, fid), _width="500", _height="500"))

请注意,I帮助程序标记已被正确的IMG替换。 'jid'是作业ID,'fid'是您要显示/下载的文件ID。

答案 2 :(得分:0)

从Web2Py视图下载

从Web2Py书中: 链接到静态文件夹中的音频或视频文件时,如果要强制浏览器下载文件而不是通过媒体播放器流式传输音频/视频,请在URL上添加“附件”。这告诉web2py将HTTP响应的Content-Disposition标头设置为“附件”。例如:

<a href="/app/static/my_audio_file.mp3?attachment">Download</a>

单击上面的链接时,浏览器将提示用户下载MP3文件,而不是立即流音频。

我已经成功地将以上内容用于json和csv文件。 请注意,以上内容不适用于 private 文件夹中的文件。

从Web2Py控制器下载

def my_download():
    directory = '2e6d2ba1-52d7-4927-b91d-c7568b25314d'
    Cat = 'foobar'

    path=os.path.join(request.folder,'static', directory + Cat + '.json')
    return response.stream(open(path,'rb'), attachment=True, filename=Cat)