Skip to main content

How to use the Downloader component

Dash File Cache provides a factory instance for implementing a component that can fire a downloading event by a callback.

downloader = Downloader(id: str)

The following codes show a comparison between the implementation with Downloader and without Downloader. They are implementations with the equivalent functionalities.

with_downloader.py
import io

from typing import Optional

import dash
from dash import html
from dash import Input
import dash_file_cache as dfc


app = dash.Dash("demo")
service = dfc.ServiceData(dfc.CachePlain(1))
service.serve(app)

downloader = dfc.Downloader("downloader", None)

app.layout = html.Div(
(
html.Div(html.Button(id="btn", children="Download")),
downloader.layout()
)
)

downloader.use_callbacks(app)


@app.callback(downloader.as_output, Input("btn", "n_clicks"))
def a_callback_creating_data(n_clicks: Optional[int]) -> str:
if not n_clicks:
return dash.no_update
address = service.register(
fobj=io.StringIO("test file data..."),
file_name="test.txt",
mime_type="text/plain",
one_time_service=True,
download=True,
)
return address


if __name__ == "__main__":
app.run()

Downloader(...) itself is not a dash component, but calling downloader.layout() will get the dash components related to this instance. download.use_callbacks(app) provides the callbacks related to using the trigger signal to fire a downloading event.

There are three steps of using Downloader(...):

  1. Use downloader.layout() to add the components to the dashboard.
  2. Use downloader.use_callbacks(app) to bind the callbacks converting a dash.Output(...) signal to the downloading event.
  3. Define a callback, where the output signal should be downloader.as_output. This value should be used for providing the address of the file to be downloaded. The address can be provided by the cache of the ServiceData(...).

Remember to specify the file_name and mark the download=True when registering the file to the cache. These options ensure that the dynamic link to the file will trigger the downloading event, and the name of the downloaded file will be specified by file_name.

Why should we use this downloader?

Until dash==2.18.x, the dcc.Download still works on the bytes data directly, which means that, the data will be encoded as bytes on the server side and sent to the client (browser). In other words, dcc.send_file is not a wrapper of flask.send_file, it cannot handle large-size data.

In comparison, our solution is based on flask.stream_with_context, and the downloader accesses the address of the file directly, which is compatible with an arbirary size of the data.

info

In the future version, we will provide a dash component which is totally compatible with the interfaces of the dcc.Download and our ServiceData, thus becoming a final solution for downloading files.