Hi Andy,

It works as you suggested below, thanks so much.

Anthony, i understand what you meant of  "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.", 
thanks for sharing your insight.

Rudy

On Monday, October 9, 2017 at 1:42:59 PM UTC+8, Andy W wrote:
>
> Hi Rudy
>
> Have you tried re-defining the download function to include the path to the
> location you have used for storing the uploaded files? For example, in my
> case I ended up with the following in my controller:
>
> def download():
>     import os
>      file_path = os.path.join(request.folder,'uploads', str(auth.user.
> client), request.args(0))
>      return response.stream(open(file_path), attachment=False, chunk_size=
> 4096)
>
>
>
> Obviously you need to edit file_path in the above to match your situation.
>
> Andy
>
> On Sunday, October 8, 2017 at 9:28:21 PM UTC+3, Rudy wrote:
>>
>> Hi Andy / Anthony,
>>
>> May i ask how you have addressed the multi-tenant requirement separating 
>> all those uploaded files from different tenant to keep track of their 
>> storage usage.
>>
>> I want to use the client id as part of the uploadfolder, it worked as a 
>> test below when I defined the uploadfolder in db.py with hardcoded 
>> client_id. In reality, the client_id varies (is there a way to specify the 
>> table company's id in the uploadfolder in db.py?), I thought of specifying 
>> the uploadfolder info in the action where I would do my upload 
>> (edit_company()), I could upload it but not download. 
>>
>> Is it the same issue as Anthony mentioned (for test purpose, i used the 
>> same edit_company()'s SQLFORM to upload and download? i thought it would 
>> execute the line 
>> db.company.logo.uploadfolder=os.path.join(request.folder,'uploads', 
>> str(company_id)) before it executes  form=SQLFORM(db.company, 
>> record=record, deletable=True, showid=True, 
>> upload=URL('download')).process(), obviously i missed out some 
>> fundamental concept (no i didn't understand why Andy couldn't specify the 
>> table definition in the module as SQLFORM and view.html would be executed 
>> after calling attachment_module.define_tables()). Any insight will be much 
>> appreciated.
>>
>> in db.py
>> client_id=3 #hard coded here for illustration
>> db.define_table('company',
>> Field('logo', 'upload', label='Company Logo', 
>>  uploadfolder=os.path.join(request.folder, 'uploads', client_id), 
>> uploadseparate=True, autodelete=True))
>>
>> in default.py
>> def edit_company():
>>     company_id = request.args(0)
>>     record=db.company(company_id)
>>     db.company.logo.uploadfolder=os.path.join(request.folder,'uploads', 
>> str(company_id))
>>     db.company.chop.uploadfolder=os.path.join(request.folder,'uploads', 
>> str(company_id))
>>     form=SQLFORM(db.company, record=record, deletable=True, showid=True, 
>> upload=URL('download')
>>                  ).process()
>>     if form.accepted:
>>         session.flash='Info: you have updated your company details!!'
>>         redirect(URL('manage_company'))
>>     elif form.errors:
>>         response.flash='Error: inside edit_company, form raised error!!'
>>     else:
>>         pass
>>     return locals()
>>
>> On Monday, May 9, 2016 at 10:29:00 PM UTC+8, 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 web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to