And in my case, using the represent option to feed an id variable to the
URL, a download function like this works:
from gluon.contenttype import contenttype
def download_dataset():
# get the id and record
ds_id = request.vars['id']
if ds_id is None:
# non-existent id provided
session.flash = "Database id not provided"
redirect(URL('datasets','administer_datasets'))
try:
ds_id = int(ds_id)
except ValueError:
# non-integer id provided
session.flash = "Database id not an integer"
redirect(URL('datasets','administer_datasets'))
record = db.datasets[ds_id]
if record is None:
# non-existent id provided
session.flash = "Database record id does not exist"
redirect(URL('datasets','administer_datasets'))
# get the file name into the download header
file_header = "attachment; filename=" + record.file_name
# set up the response
response.headers['ContentType'] = contenttype(record.file_name)
response.headers['Content-Disposition'] = file_header
# get a stream of the file
path = os.path.join(request.folder, 'uploads', 'datasets',
str(record.dataset_id), record.file)
stream = open(path, 'rb')
return response.stream(stream)
On Saturday, 3 February 2018 21:44:23 UTC, David Orme wrote:
>
> Thanks, Anthony. So to sum up what I think the options are:
>
> 1) The code laying out the standard SQLFORM.grid record view handles the
> display of each field and - for upload fields - the download link uses:
>
> https://.../controller/sqlform_grid_function/download/file_name
>
> That can be changed using the upload argument to SQLFORM grid. If you pass
> in a string (like the output of URL) then file name value is appended, so:
>
> form = SQLFORM.grid(..., upload = URL('dataset', 'download_dataset'), ...)
>
> will set the download link to:
>
> https://.../dataset/download_dataset/file_name
>
> You can pass in a function instead, in which case the output of the
> function is used as the link (*without* appending the file name value).
> So if you do:
>
> form = SQLFORM.grid(..., upload = lambda value: URL('datasets',
> 'download_dataset'), ...)
>
> then the link is not terribly functional:
>
> https://.../dataset/download_dataset
>
> The only local variable that function has access to is the file name, so
> this bit of code provides a function that duplicates just providing the URL
> as a string:
>
> form = SQLFORM.grid(..., upload = lambda value: URL('datasets',
> 'download_dataset', value), ...)
>
> That isn't particularly useful, but the value could be used in a more
> complex way. For example, as Anthony says, by looking up the filename
> (which will be unique, thanks to the random component of the internal file
> names) in the database table and using this to populate a link with the
> custom download information. For example, this function allows the URL to
> be expanded to use other parts of the record for that file:
>
> def _lookup(value):
> record = db(db.datasets.file == value).select().first()
> return URL('datasets','download_dataset', args=[record.dataset_id,
> record.file])
>
> form = SQLFORM.grid(..., upload = lambda value: _lookup(value), ...)
>
> That produces links like this (for a record with dataset_id = 15):
>
> https://.../datasets/download_dataset/15/file_name
>
> I don't think there is any way to get the default download controller to
> know about the nested download - it uses the field.retrieve method to get
> the data and that doesn't know about the record specific upload folder. So,
> I think you *have to* then use a custom function to provide the download.
>
> Another alternative is to change the representation of the file field in
> the controller function before creating the SQLFORM.grid. For example:
>
> db.datasets.file.represent = lambda value, row: A('Download file', _href=
> URL('datasets', 'download_dataset', vars={'id': row.id}))
>
> I thought that would derail the upload widget in the SQLFORM edit view but
> it doesn't seem to. Its probably a simpler way to get a custom download
> link that points to the record rather than just the filename, but doesn't
> get around the need for a custom download function.
>
>
> On Saturday, 3 February 2018 17:37:32 UTC, Anthony wrote:
>>
>> On Saturday, February 3, 2018 at 1:58:26 AM UTC-5, David Orme wrote:
>>>
>>> So at the moment, what users are seeing is a controller presenting
>>> SQLFORM.grid of dataset records, and then in the 'view' argument to that
>>> controller for a particular record, the file field is shown as the output
>>> of the represent method of UploadWidget (so the word 'file' wrapped up
>>> with the download link, which is ignorant of the subfolder). It isn't
>>> obvious to me that there is a way to insert new_ds_id into that mechanism?
>>>
>>
>> The "upload" argument of SQLFORM.grid can be a function that takes the
>> value and returns a URL, but you are still stuck having to figure out the
>> URL from the filename, which will require a database lookup per row of the
>> grid. An alternative is to not display the default file column in the grid
>> and instead use the "links" argument to generate a custom column with
>> custom download links (see "links" under
>> http://web2py.com/books/default/chapter/29/07/forms-and-validators#SQLFORM-grid-signature).
>>
>> Another option is to create a custom column using a virtual field.
>>
>> Anthony
>>
>
--
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.