Upload a CSV / xlsx file in Dash from local and save to the file in define specific directory

Hello Team,

I am developing a dashboard in Dash with Python and in one of the core components. I am trying to upload a csv file / xlsx file from local folder. Instead of display the dataframe, I would like to save the file in specific directory.

How can I define the callback & define function. So the file will be stored in folder.

Thanks for your support in advance…!!!

Best Regards,
Gaurav Rajendra

Hey @GAURAV2689,

I guess your app is running locally. How are you providing the directory in which to save the file? Which format do you want it to be stored?

Hi @AIMPED,

Thanks for your reply.

I would like to achieve the desired functionality in Dash, I want to use the dcc.Upload component to allow users to upload a file from their local drive [Microsoft Excel Worksheet (.xlsx)]. and save the same excel to a specific directory on server on defined folder path…

So this standard format [Microsoft Excel Worksheet (.xlsx)], I will use for postprocessing. I don’t want to convert the contents to a DataFrame.

First I tried with creating the dataframe and save the file, but It is showing error.

Capture

Best Regards,

Please find my below code.

import os
import pandas as pd
import dash
from dash import dcc
from dash import html

# Set the upload folder path
UPLOAD_FOLDER = '/TestReport/'

# Define the Dash app
app = dash.Dash(__name__)

# Define the upload component
upload_component = dcc.Upload(
    id='upload-data',
    children=html.Div([
        'Drag and drop or ',
        html.A('select a file')
    ]),
    style={
        'width': '50%',
        'height': '60px',
        'lineHeight': '60px',
        'borderWidth': '1px',
        'borderStyle': 'dashed',
        'borderRadius': '5px',
        'textAlign': 'center',
        'margin': '10px'
    },
    multiple=False
)

# Define the callback function to save the uploaded file
@app.callback(
    dash.dependencies.Output('output-data-upload', 'children'),
    dash.dependencies.Input('upload-data', 'contents')
)
def save_file(contents):
    if contents is not None:
        # Convert the contents to a DataFrame
        df = pd.read_excel(contents)
        
        # Save the DataFrame to the upload folder
        file_path = os.path.join(UPLOAD_FOLDER, 'uploaded_file.xlsx')
        df.to_excel(file_path, index=False)
        
        # Return a message to confirm that the file was saved
        return html.Div([
            'File saved to ',
            html.A(file_path, href=file_path)
        ])

# Define the layout of the app
app.layout = html.Div([
    upload_component,
    html.Div(id='output-data-upload')
])

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True, use_reloader=False)

Hi @GAURAV2689 you can’t do this:

You have to parse the uploaded content first. Take a look at this example:

Hi

I got the solution from internet. Please check below code.

This code, we can keep for others help.

Thanks & Regards,
Gaurav Rajendra

import base64
import os
from urllib.parse import quote as urlquote

from flask import Flask, send_from_directory
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output


UPLOAD_DIRECTORY = "/project/app_uploaded_files"

if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)


# Normally, Dash creates its own Flask server internally. By creating our own,
# we can create a route for downloading files directly:
server = Flask(__name__)
app = dash.Dash(server=server)


@server.route("/download/<path:path>")
def download(path):
    """Serve a file from the upload directory."""
    return send_from_directory(UPLOAD_DIRECTORY, path, as_attachment=True)


app.layout = html.Div(
    [
        html.H1("File Browser"),
        html.H2("Upload"),
        dcc.Upload(
            id="upload-data",
            children=html.Div(
                ["Drag and drop or click to select a file to upload."]
            ),
            style={
                "width": "100%",
                "height": "60px",
                "lineHeight": "60px",
                "borderWidth": "1px",
                "borderStyle": "dashed",
                "borderRadius": "5px",
                "textAlign": "center",
                "margin": "10px",
            },
            multiple=True,
        ),
        html.H2("File List"),
        html.Ul(id="file-list"),
    ],
    style={"max-width": "500px"},
)


def save_file(name, content):
    """Decode and store a file uploaded with Plotly Dash."""
    data = content.encode("utf8").split(b";base64,")[1]
    with open(os.path.join(UPLOAD_DIRECTORY, name), "wb") as fp:
        fp.write(base64.decodebytes(data))


def uploaded_files():
    """List the files in the upload directory."""
    files = []
    for filename in os.listdir(UPLOAD_DIRECTORY):
        path = os.path.join(UPLOAD_DIRECTORY, filename)
        if os.path.isfile(path):
            files.append(filename)
    return files


def file_download_link(filename):
    """Create a Plotly Dash 'A' element that downloads a file from the app."""
    location = "/download/{}".format(urlquote(filename))
    return html.A(filename, href=location)


@app.callback(
    Output("file-list", "children"),
    [Input("upload-data", "filename"), Input("upload-data", "contents")],
)
def update_output(uploaded_filenames, uploaded_file_contents):
    """Save uploaded files and regenerate the file list."""

    if uploaded_filenames is not None and uploaded_file_contents is not None:
        for name, data in zip(uploaded_filenames, uploaded_file_contents):
            save_file(name, data)

    files = uploaded_files()
    if len(files) == 0:
        return [html.Li("No files yet!")]
    else:
        return [html.Li(file_download_link(filename)) for filename in files]


if __name__ == "__main__":
    app.run_server(debug=True, port=8888)