【问题标题】:Web2py: downloading files / displaying imagesWeb2py:下载文件/显示图像
【发布时间】:2012-09-14 10:44:54
【问题描述】:

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

上下文

我正在构建的网站是科学代码的界面:人们填写表格并提交。数据(写入共享文件夹内的文件)然后由代码处理,在后台作为守护进程运行(代码与网站没有链接,除了这个共享文件夹和code->website之间的 JSONRPC 链接) . 该代码会生成我希望向网站用户提供的文件和图像(即,将他们要求的结果返回给他们)。 工作完成后,代码使用 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 :) 与推特引导程序中使用的I 标签混淆而产生的简单错误对于图标...这样就解决了显示问题。 对于流文件而不在上传文件夹中复制它们(即不使用数据库中的upload 字段),rochacbruno(非常感谢他)让我走上了正轨。请参阅我自己的答案以获得完整的解决方案。

【问题讨论】:

    标签: python image file download web2py


    【解决方案1】:

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

    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。

    【讨论】:

    • 这是一篇很棒的小帖子,但是 contenttype 变量从何而来?我们应该在您的解决方案中解决这个问题吗?
    • 天哪,你是对的!它是 gluon.contenttype 模块中可用的功能。在这里查看官方示例:web2py.com/init/default/examples(示例 11)。
    【解决方案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和默认存储方式一起使用。

    【讨论】:

    • 感谢您的回答...但我认为您的 sn-p 有问题,不是吗? response.stream 应该采用文件对象,而不是路径。我找到了解决我的问题的方法。无论如何,再次感谢,你让我走上了正轨
    • 上面的代码不起作用。尝试返回 response.stream(open(path,'rb'), attachment=True, filename='foo')
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多