UploadHandler uploads files

From v1.59 UploadHandler is deprecated. Use DriveHandler.

UploadHandler lets you upload files and manage them. Here is a sample configuration:

url:
  uploadhandler:
    pattern: /$YAMLURL/upload
    handler: UploadHandler
    kwargs:
      path: $GRAMEXDATA/apps/guide/upload/    # ... save files here

By default, .meta.db keystore is created in kwargs:path directory to store uploaded files’ metadata. You can configure store as follows:

url:
  uploadhandler:
    pattern: /$YAMLURL/upload
    handler: UploadHandler
    kwargs:
      path: $GRAMEXDATA/apps/guide/upload/
      store:
        type: sqlite
        path: $GRAMEXDATA/apps/guide/upload/.fileinfo.db
        flush: 5

The type: can define any valid store type as seen in session data.

Note: Till 1.37 type: hdf5 was the default. From 1.38 onwards type:sqlite is defaulted.

Any file posted with a name of file is uploaded. Here is a sample HTML form:

  <form action="upload" method="POST" enctype="multipart/form-data">
    <input name="file" type="file">
    <button type="submit">Submit</button>
    <input type="hidden" name="_xsrf" value="{{ handler.xsrf_token }}">
  </form>

(See the XSRF documentation to understand xsrf_token.)

After the file is uploaded, users can be redirected via the redirect: config documented the redirection configuration.

AJAX uploads

DropZone provides drag-and-drop AJAX uploads with progress bars. For example:

<link rel="stylesheet" href="ui/dropzone/dist/min/dropzone.min.css">
<form action="upload" class="dropzone"></form>
<script src="ui/dropzone/dist/min/dropzone.min.js"></script>

creates this box:

Saving uploads

By default, the file is saved in the path: specified by gramex.yaml, with the filename passed by the browser.

You can change the path where the file is saved using <input name="save">. See the example below:

<form action="upload" method="POST" enctype="multipart/form-data">
  <input name="file" type="file">
  <button type="submit">Submit</button>
  <input type="hidden" name="save" value="folder/data.csv">
  <input type="hidden" name="_xsrf" value="{{ handler.xsrf_token }}">
</form>

This saves the file under folder/data.csv, which is under the path: section specified by gramex.yaml. folder/ is created if required.

If multiple file uploads are present, multiple save fields can be used to specify the filenames in order.

If the save value refers to a path outside of the path: specified, the handler returns a HTTP 403.

To disable users from overwriting the filename, you can set keys.save: [] in gramex.yaml. See Upload arguments

Overwriting uploads

If the target location already exists, there are 4 ways of handling it. This is specified by the overwrite: key in gramex.yaml.

    handler: UploadHandler
    kwargs:
      path: ...
      if_exists: error        # Raises a HTTP 403 with a reason saying "file exists"
      if_exists: backup       # Move the original to filename.YYYYMMDD-HHMMSS.ext
      if_exists: overwrite    # Overwrite the original without backup
      if_exists: unique       # Save to a new file: filename.1, filename.2, etc

Upload listing

You can retrieve the list of files uploaded via AJAX if you include a methods: GET in the kwargs: section as follows:

url:
  uploadhandler:
    pattern: /$YAMLURL/upload
    handler: UploadHandler
    kwargs:
      path: $GRAMEXDATA/apps/guide/
      methods: get                   # GET /upload returns file info as JSON

The list of files uploaded can be retrieved from the upload URL, along with associated information:

You can also retrieve the data in Python via FileUpload(path).info().

import gramex.handlers.uploadhandler
uploader = gramex.handlers.uploadhandler.FileUpload(path)
return uploader.info()

The uploader.info() is a list of info objects with the following keys:

Upload deletion

To delete a file, submit a POST request to the UploadHandler with a delete key. Here is a sample AJAX request:

$.ajax('upload', {
  method: 'POST',
  data: {'delete': file}  // Use the 'file' attribute in uploader.info()
})

Upload arguments

By default, UploadHandler uses these form keys:

You can change the keys used via the keys: configuration.

url:
  uploadhandler:
    pattern: ...
    handler: UploadHandler
    kwargs:
      path: ...
      keys:                     # Define what query parameters to use
        file: [file, upload]    # Use <input id="file"> and/or <input id="upload">
        delete: [del, rm]       # Use <input id="del"> and/or <input id="rm">
        save: [save]            # Use <input id="save"> to specify the save location

To prevent users from changing or setting the filename, use:

    keys:
      save: []    # No field names can override the user provided filename

Process uploads

UploadHandler accepts a transform: config that processes the files after they have been saved. For example:

url:
  uploadhandler:
    pattern: ...
    handler: UploadHandler
    kwargs:
      path: ...
      transform:
        function: module.func(meta, handler)

This calls module.func(meta, handler) where meta is an AttrDict with the keys mentioned in Upload listing. For example, this function will save CSV files as data.json:

def func(meta, handler):
  if meta.mime == 'text/csv':
    path = os.path.join('... upload path ...', meta.file)
    pd.read_csv(path).to_json('data.json')

If module.func() returns a value, it replaces the file metadata. This allows you to add / modify delete keys in the Upload listing.

If no args or kwargs are specified, the transform function is called with (meta, handler) as the keyword arguments.