Web2py: downloading files / displaying images

巧了我就是萌 提交于 2019-12-07 00:30:01

You have to create your own download function

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

The default/download is intended to be used with db and the default way of storing.

So here is the complete solution to my problem.

In the db.py file, I've replaced the 'file' table by this definition (so files stay where they are, and are not copied into the web2py upload folder):

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

Then, in a controller (eg. 'mycontroller'), I've defined this function to stream files:

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

Please note, that I ran into another problem at this point: I first thought to pass the full path as a request argument (eg. URL(c='mycontroller', f='export', args=(path, filename))), but it did not work since path was containing '/' that were split into as many arguments... If you don't have an easy path like me (ie. just one component change), you can store the path into the 'file' DB for instance.

Then, for the view (using either a module or whatever you like):

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

Notice that the I helper tag has been replaced by the correct IMG one. 'jid' is the job ID, and 'fid' is the file ID you want to display/download.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!