Dynamic Upload Uploadfolder

100 views
Skip to first unread message

James Burke

unread,
Nov 29, 2014, 3:08:20 PM11/29/14
to web...@googlegroups.com
How do you create a dynamic uploadfolder for an upload Field?

I tried using:
uploadfolder= lambda r: db.repository(r.repository_id).directory

but i get the error message, I guess it doesn't have the same functionality as compute: 

cannot concatenate 'str' and 'function' objects


I'm also using custom_store/retreive to maintain the files original filename

def store_file(file, filename=None, path=None):
    path
= path # "applications/init/uploads"
   
if not os.path.exists(path):
         os
.makedirs(path)
    pathfilename
= os.path.join(path, filename)
    dest_file
= open(pathfilename, 'wb')
   
try:
            shutil
.copyfileobj(file, dest_file)
   
finally:
            dest_file
.close()
   
return filename


If I can set the uploadfolder dynamically then it's passed to store_file as path.

I also tried:
path = db.repository(db.workbench(db.workbench.name==filename).repository).directory

But it can't find a record, I guess because store_file is run before the record is created in the db.

Any suggestions?

Thank you!

Massimo Di Pierro

unread,
Nov 30, 2014, 5:46:57 PM11/30/14
to web...@googlegroups.com
You cannot do this uploadfolder= lambda r:...
But this is a chicken-egg problem. You want r to be the row but the row is not created until after the file is uploaded therefore you cannot specify the upload folder as function of something that happens after.

Please explain to us in english of the folder should depend on the upload and perhaps we can suggest a way to do it.

James Burke

unread,
Nov 30, 2014, 6:27:57 PM11/30/14
to web...@googlegroups.com
Thank you for your help Massimo.

My model is defined as follows:
## Repository

db.define_table('repository',
        Field('name', type='string'),
        Field('directory', default='applications/init/uploads'),
        format='%(name)s')

## Workbench - workbenches stored in the repository

db.define_table('workbench',
        Field('repository', 'reference repository'),
        Field('name', compute=lambda r: db.workbench.workbench.retrieve(r.workbench)[0]),
        Field('workbench', type='upload', required=True, custom_store=store_file, custom_retrieve=retrieve_file ),
        Field('sequence', 'integer', required=True),
        Field('created_date', 'datetime', default=request.now, readable=False, writable=False),
        Field('modified_date', 'datetime', update=request.now, readable=False, writable=False),
        format='%(name)s')

I have a Repository table which is joined to the Workbench table (1:M - a repository can have many workbenches )

In my controller I have a smartgrid for Repository which has Workbenches as a linked table. After a Repository has been created, the user can create Workbenches linked to the Repository. When creating the Workbench I want the workbench file to be uploaded to the directory in the Repository location field.

I hope that makes it clear what I'm trying to achieve.

Thank you.

James Burke

unread,
Dec 2, 2014, 12:45:45 AM12/2/14
to web...@googlegroups.com
Any ideas?

Cheers


On Monday, December 1, 2014 11:46:57 AM UTC+13, Massimo Di Pierro wrote:

Leonel Câmara

unread,
Dec 2, 2014, 4:28:49 AM12/2/14
to web...@googlegroups.com
There are lots of ways to do this, the easiest is probably to just define the uploadfolder for the field in the controller for workbench creation/update instead of defining your custom store and retrieve. Something like this:


def create_workbench():
   
""" Form to create a workbench in a given repository """
    rep
= db.repository[request.args(0)]
   
if rep is None:
       
raise HTTP(404)
    db
.workbench.workbench.uploadfolder = rep.directory
    form
= SQLFORM(db.workbench)
   
if form.process().accepted:
        response
.flash = 'Yay'
   
elif form.errors:
        response
.flash = 'Nay'


def update_workbench():
   
""" Form to update a workbench """
    wb
= db.worbench[request.args(0)]
    db
.workbench.workbench.uploadfolder = wb.repository.directory
    form
= SQLFORM(db.workbench, wb)
   
if form.process().accepted:
        response
.flash = 'Yay'
   
elif form.errors:
        response
.flash = 'Nay'

I haven't tried it, but this should work if you remove your custom store and retrieve.



James Burke

unread,
Dec 2, 2014, 12:19:26 PM12/2/14
to web...@googlegroups.com
Thank you Leonel, great idea.

Although I'll need to use oncreate/onupdate since I'm using a smartgrid

Cheers,

-James

James Burke

unread,
Dec 3, 2014, 12:21:09 PM12/3/14
to web...@googlegroups.com
Final solution was this:

_tables.py
def store_file(file, filename=None, path=None):
    path
= path #"applications/init/uploads"
   
if not os.path.exists(path):
         os
.makedirs(path)
    pathfilename
= os.path.join(path, filename)
    dest_file
= open(pathfilename, 'wb')
   
try:
            shutil
.copyfileobj(file, dest_file)
   
finally:
            dest_file
.close()
   
return filename


## Repository


db
.define_table('repository',
   
Field('name', type='string'),
   
Field('directory', default='applications/init/uploads'),

   
Field('priority', 'integer', default=100),
    format
='%(name)s')


## File - Files stored in the repository



db
.define_table('workbench',
   
Field('repository', 'reference repository'),

   
Field('name')
   
Field('workbench', type='upload', required=True, custom_store=store_file, custom_retrieve=retrieve_file), #  

   
Field('sequence', 'integer', required=True),
   
Field('created_date', 'datetime', default=request.now, readable=False, writable=False),
   
Field('modified_date', 'datetime', update=request.now, readable=False, writable=False),
    format
='%(name)s')

Repository.py
def onvalidation(form):
    repository
= db.repository(form.vars.repository)
   
if repository is None:
       
raise HTTP(404)
    db
.workbench.workbench.uploadfolder = repository.directory


def oncreate(form):
    db
(db.workbench.id==form.vars.id).update(name=form.vars.workbench)


def onupdate(form):
    db
(db.workbench.id==form.vars.id).update(name=form.vars.workbench)


def index():
   
"""
    Additional code here
    """

    form
= SQLFORM.smartgrid(db.repository,
                            fields
=fields,
                           
orderby=orderby,
                            searchable
=True,
                            details
=details,
                            editable
=editable,
                            deletable
=deletable,
                            oncreate
=oncreate,
                            onupdate
=onupdate,
                            onvalidation
=onvalidation,
                            links
=links,
                            paginate
=paginate,
                            linked_tables
=linked_tables)


   
return dict(form=form)

Need to use onvalidation to set the upload directory, oncreate is executed after the record is created.

Reply all
Reply to author
Forward
0 new messages