使用Dash Upload组件发布CSV文件

时间:2019-12-21 09:56:20

标签: csv post python-requests postman plotly-dash

我想使用Dash Upload组件(请参见Example from Dash Documentation)上传一个csv文件并将其发布到文件服务器。我希望它像这个working Postman csv Post-Request一样简单。 我的回调目前看起来像这样:

@app.callback(
Output(component_id="eventlog-dropdown", component_property="options"),
[Input(component_id="upload-data", component_property="contents"),
 Input(component_id="upload-data", component_property="filename")]
)
def upload_eventlog(uploaded_contents, uploaded_filename):
    if uploaded_contents is not None:
        eventlog_data = [
            parse_contents(c, n) for c, n in
            zip(uploaded_contents, uploaded_filename)]

        files = {'file': (uploaded_filename[0], str(eventlog_data))}

        print(files)

        requests.post(MIDDLEWARE_ENDPOINT+"data/upload-eventlog", files=files)

        #Updates the dropdown "eventlog-dropdown"
        files = requests.get(MIDDLEWARE_ENDPOINT + 'data/geteventloglist').json()
        options = [{'label': i, 'value': i} for i in files]
        return options
    elif uploaded_contents is None:
        files = requests.get(MIDDLEWARE_ENDPOINT + 'data/geteventloglist').json()
        options = [{'label': i, 'value': i} for i in files]
        return options

解析内容函数如下所示:

def parse_contents(contents, filename):
content_type, content_string = contents.split(',')

decoded = base64.b64decode(content_string)
try:
    if 'csv' in filename:
        # Assume that the user uploaded a CSV file
        df = pd.read_csv(
            io.StringIO(decoded.decode('utf-8')))
        return df
    elif 'xls' in filename:
        # Assume that the user uploaded an excel file
        df = pd.read_excel(io.BytesIO(decoded))
        return df
except Exception as e:
    print(e)
    return html.Div([
        'There was an error processing this file.'
    ])

帖子“有效”。它发布了csv文件,并且csv文件正在存储在文件服务器上。但是,csv不再被逗号分隔并被截断:

69  FN322        Landing  2019-05-22 04:35         Berlin       12:20      4           12.333333
70  FN322  Baggage claim  2019-05-22 03:05         Berlin       01:40      5            1.666667

[71 rows x 7 columns]]

你们知道有什么简单的方法可以像Postman一样在Dash Upload组件中发布上传的文件名和内容吗?或至少如何保存所有文件内容?

非常感谢您,并祝您愉快!

1 个答案:

答案 0 :(得分:0)

我知道了。这是由于以下几行代码:

`df = pd.read_csv(
    io.StringIO(decoded.decode('utf-8')))`

要上传csv文件,我们不希望它成为文本流。它必须是类似字节的对象。代码:

decoded = base64.b64decode(content_string)

已经返回一个字节对象,这样我们只需要返回那个对象。因此,parse_contents()函数现在如下所示:

def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)

    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            return decoded
     except Exception as e:
        return html.Div([
        'There was an error processing this file.'
    ])

请注意,我目前仅对csv文件感兴趣。这就是为什么我删除了xlsx部分。不幸的是,我不知道该代码是否也适用于xlsx文件。 代码

eventlog_data = [
        parse_contents(c, n) for c, n in
        zip(uploaded_contents, uploaded_filename)]

定义一个列表,其中已解码的字节对象是该列表中的第一个元素。因此,我们后请求的文件参数必须采用eventlog-data的第一个元素才能发送字节数据:

files = {'file': (uploaded_filename[0], eventlog_data[0])}

最终的回调如下:

@app.callback(
Output(component_id="eventlog-dropdown", component_property="options"),
[Input(component_id="upload-data", component_property="contents"),
 Input(component_id="upload-data", component_property="filename")]
)
def upload_eventlog(uploaded_contents, uploaded_filename):
    if uploaded_contents is not None:
        eventlog_data = [
            parse_contents(c, n) for c, n in
            zip(uploaded_contents, uploaded_filename)]
        files = {'file': (uploaded_filename[0], eventlog_data[0])}
        requests.post(MIDDLEWARE_ENDPOINT+"predictivemonitor/upload-eventlog", files=files)

        #Updates the dropdown "eventlog-dropdown"
        files = requests.get(MIDDLEWARE_ENDPOINT + 'predictivemonitor/geteventloglist').json()
        options = [{'label': i, 'value': i} for i in files]
        return options
    elif uploaded_contents is None:
        #Still updates the dropdown "eventlog-dropdown" even if the content is empty
        files = requests.get(MIDDLEWARE_ENDPOINT + 'predictivemonitor/geteventloglist').json()
        options = [{'label': i, 'value': i} for i in files]
        return options