2

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

语境

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

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

当前的实现(不能正常工作)

目前我有 3 个数据库:

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

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

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

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

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"))

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

问题

这只是行不通......显示页面的源代码如下:

<i height="500" src="/mycode/default/download//path/to/directory/file.file.9b7d3a0367de0843.6d732d72732e706e67.png" width="500"></i>

如果我在地址栏中输入此 URL,则文件下载正确,否则图像不会显示在网页上。此外,我必须提供文件的路径,即使 Web2py 确实将文件复制到“上传”文件夹中(使用其新的安全丑名称:)),否则链接不起作用。所以:没有显示图像,而且文件无论如何都会复制到“上传”文件夹中:(

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

编辑(解决方案)

好吧,我的代码中有一个明显的错误,我错过了:图像标签助手不是I,但是IMG:) 与 twitter bootstrap 图标中使用的标签混淆引起的简单错误I......这样就解决了显示问题。对于流文件而不在上传文件夹中复制它们(即不使用upload数据库中的字段),rochacbruno(非常感谢他)让我走上了正确的轨道。有关完整解决方案,请参阅我自己的答案。

4

3 回答 3

2

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

db.py文件中,我用这个定义替换了“文件”表(因此文件保留在原处,并且不会复制到 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包含被拆分为多个参数的“/”。 . 如果您没有像我这样的简单路径(即仅更改一个组件),您可以将路径存储到“文件”数据库中。

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

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。

于 2012-09-22T19:09:45.137 回答
1

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

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 和默认存储方式一起使用。

于 2012-09-22T04:27:58.900 回答
0

从 Web2Py 视图下载

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

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

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

我已经成功地将上述内容与 json 和 csv 文件一起使用。请注意,上述内容不适用于私人文件夹中的文件。

从 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)
于 2020-09-05T21:18:24.820 回答