Many thanks for the clear explanation!
Andy
On Monday, May 9, 2016 at 7:28:49 PM UTC+4, Anthony wrote:
>
> Assuming you are talking about the standard download() function in the
> default.py controller of the scaffolding application, note that it uses
> response.download() to retrieve the file, and as per the documentation, it
> looks at only the *last* URL arg to obtain the filename (from which it
> extracts the database table name and field name in order to get the
> uploadfolder and retrieve the file). So, in your link URL:
>
> URL('download', args=(str(client_id) + '/attachments/' + r['attached_file'
> ])
>
> The str(client_id) and "attachements" parts of the URL are completely
> ignored and therefore unnecessary.
>
> Of course, because response.download() works by getting the uploadfolder
> from the upload field definition, it requires that the relevant database
> model actually be defined. In your case, though, you are only defining the
> db.attachment_module table when inside the module_based() function, so when
> in the download() function, that model doesn't exist, and
> response.download() therefore cannot find the relevant upload folder.
>
> If you don't want to have to ensure that the model has been defined when
> the download() function is called, you can continue using links like the
> ones you have generated, but in that case you won't be able to use
> response.download() and should instead use response.stream(). The former is
> designed to work specifically with upload fields in DAL models (and
> therefore requires access to the models), whereas the latter is a more
> general method for streaming any file back to the browser (though it
> requires that you know the full path to the file on the filesystem).
>
> Anthony
>
> On Monday, May 9, 2016 at 10:29:00 AM UTC-4, Andy W wrote:
>>
>> I have a multi-tenant application, where users can upload files. I save
>> these in a different directory for each client (tenant), so I can keep tabs
>> on the overall disk space and number of files uploaded by each.
>>
>> This works fine when the table is defined in a model file - from the view
>> I can download existing files and upload new ones:
>>
>> Model:
>> from gluon import *
>> import os
>> client_id=3 #hard coded here for illustration
>>
>> db.define_table('attachment_model',
>> Field('attached_file', 'upload', label="Upload new file",
>> uploadfolder=os.path.join(request.folder, 'uploads', str(
>> client_id), 'attachments'),
>> requires=IS_NOT_EMPTY(), autodelete=True),
>> Field('filename', type='string', length=150, writable=False),
>> migrate=True)
>>
>> Controller:
>> def model_based():
>> db.attachment_model.filename.readable=False
>> form_attachment=SQLFORM(db.attachment_model,
>> autodelete=True, labels=None, deletable=True,
>> fields=['attached_file'], submit_button='Attach file')
>> if hasattr(request.vars.attached_file, "filename"):
>> #save original file name
>> form_attachment.vars.filename=request.vars.attached_file.filename
>> if form_attachment.process().accepted:
>> response.flash = 'attachment saved'
>> elif form_attachment.errors:
>> response.flash = 'form has errors'
>> # list existing attachments
>> rows=db(db.attachment_model.id>0).select()
>> response.view = 'attachment.html'
>> return dict(form_attachment=form_attachment,
>> rows=rows)
>>
>> View:
>> {{extend 'layout.html'}}
>> <h1>
>> Attached files
>> </h1>
>> <table class="table-striped">
>> <thead>
>> <tr>
>> <td>id</td>
>> <td>filename</td>
>> </tr>
>> </thead>
>> <tbody>
>> {{for r in rows:}}
>> <tr>
>> <td>{{=r.id}}</td>
>> <td>{{=A(r.filename, _href=URL('download', args=(str(
>> client_id) + '/attachments/' + r['attached_file'])))}}</td>
>> </tr>
>> {{pass}}
>> </tbody>
>> </table>
>>
>> <h2>Add new attachment</h2>
>> <div class="form-inline well">
>> {{=form_attachment}}
>> </div>
>>
>> My issue is when I re-write the above so the model definition is moved to
>> a module.
>>
>> Module mod_attachment.py:
>> from gluon import *
>> import os
>>
>> class Attachment_module(object):
>> def __init__(self, db):
>> self.db = db
>>
>> def define_tables(self):
>> db = self.db
>> client_id=3
>> if not 'attachment_module' in db.tables:
>> db.define_table('attachment_module',
>> Field('attached_file', 'upload', label="Upload new file",
>> uploadfolder=os.path.join(current.request.folder,
>> 'uploads', str(client_id), 'attachments'),
>> requires=IS_NOT_EMPTY(), autodelete=True),
>> Field('filename', type='string', length=150, writable=
>> False),
>> Field('request_tenant', type='integer', default=client_id
>> ,
>> readable=False, writable=False),
>> migrate=True)
>>
>> Revised controller:
>> def module_based():
>> from mod_attachment import Attachment_module
>> attachment_module = Attachment_module(db)
>> attachment_module.define_tables()
>> db.attachment_module.filename.readable=False
>> form_attachment=SQLFORM(db.attachment_module,
>> autodelete=True, labels=None, deletable=True,
>> fields=['attached_file'], submit_button='Attach file')
>> if hasattr(request.vars.attached_file, "filename"):
>> #save original file name
>> form_attachment.vars.filename=request.vars.attached_file.filename
>> if form_attachment.process().accepted:
>> response.flash = 'attachment saved'
>> elif form_attachment.errors:
>> response.flash = 'form has errors'
>> # list existing attachments
>> rows=db(db.attachment_module.id>0).select()
>> response.view = 'attachment.html'
>> return dict(form_attachment=form_attachment,
>> rows=rows)
>>
>> With this approach, I can still list the uploaded files and add
>> additional ones (using the same view as before), but the download function
>> no longer works.
>>
>> So my question is why not? Do I have to modify the standard download
>> function, and how?
>> Hope these are not daft questions - any pointers would be appreciated.
>>
>> Andy
>>
>>
>>
>>
>>
>>
>>
--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.