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 [email protected].
For more options, visit https://groups.google.com/d/optout.