Using multiple tables in the same page as you know requires explicitly adding form name when you accept it
suppose a situation in which you need to make multiple upload forms in the same page may be for users to upload their cvs
Now you’ve 3 problems :
- How could you add multiple forms in the same page and in the same time make them work ?
- How to upload the files (cvs)
- How to download them
jobs = db(...).select(...)
for job in jobs:
# I'll use the same name for form name as well as the field
formname = "upload_f_%s"%job.id
form = FORM(INPUT(_type="file",_name=formname,
IS_LENGTH(1048576, 1024, error_message=CustomMessages.UPLOAD_CV_SIZE)
if form.accepts(request.vars, formname=formname):
file_id = db.cvs.insert(cv=db.cvs.cv.store(stream,filename=filename),
# add permissions for that file
# do other stuff
As you see , I made a form with a field of type ‘file’ and form name is variable based on the job_id , C.Vs are going to be uploaded
this helps making multiple forms per page and in the same time every form has a unique name that will be used when accepting the form .
Now as you may have guessed the form containing a ‘file’ field will have (when being accepted) :
form.vars.field_name.file -> get the reference to the file
form.vars.field_name.filename -> get the file name
Now you can easily do something like:
Now you can store your file name into the database
see the :
Congratulations !!! you’ve uploaded your files
Now for downloading files you can do :
file_id = request.args(0)
import contenttype as c
(filename,file) = db.cvs.cv.retrieve(db.cvs[file_id].cv)
response.headers['Content-Type'] = c.contenttype(filename)
response.headers['Content-Disposition'] = \
"attachment; filename=%s" % filename
Now you can make another function that list all cvs available with a link for downloading them as follows:
cvs = db(db.cvs.id>0).select(db.cvs.cv) # db.cvs.cv is of type 'upload'
urls = [A('Download', _href=URL(r=request,\
)) for row in cvs]
what is the benefit of writing my own download function ?
This enables you to write your own authorization logic before allowing a user to download a file
Now what if I just don’t want to write my own download function and use web2py facilities for that matter ?
You can use response.stream(), or response.download() functions.
What is difference between them?
In fact response.stream is the main download function that takes care of streaming files.
response.download() calls response.stream() to do the streaming stuff.
response.download() has its arguments as request, db and is used for downloading files by their names, while the name is the name of the file in the database.
return response.download(request, db)
#downloads from http://..../download/filename
response.download() takes request to extract from it the file name stored in [request.args]
download function is mainly used by SQLFORM to update a record that includes an upload field that is used to upload an image, in this case response.download() gets the file (image) to be displayed when updating this record.
form = SQLFORM(db.my_table, record, upload=URL(r=request, c='default', f='download'))
Suppose you want to stream an MP3 file, you can do something like:
Somebody asked how to stream an mp3 file from the uploads files directly: