How to render dash data table after updating

931 views Asked by At

I'm creating a task manager and my goal is to have it open up, show what's already in the table and then create new tasks and show them in the data table when you click submit.

I have it so that without the callback, the page shows up like it should with the populated table. With the callback, it comes back as an empty table and my submit button doesn't seem to actually insert into my table.

I tried creating a new callback that just outputs the table, but I can't use Output('data-table', 'data') twice.

Can anyone help me see what I'm missing/doing wrong?

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_table
import dash_table.FormatTemplate as ft
import pandas as pd
import sqlite3
from datetime import datetime as dt

conn = sqlite3.connect('BI_Requests.db')
cur = conn.cursor()
#cur.execute("DELETE FROM bi_requests")
cur.execute("CREATE TABLE IF NOT EXISTS bi_requests (id_num integer, "
                "email text, request_title text, request_details text, due_date date, date_requested date)")
conn.commit()


df = pd.read_sql("SELECT email, request_title, request_details, due_date, date_requested FROM bi_requests;", conn, parse_dates=['due_date','date_requested'])
df['due_date'] = pd.to_datetime(df['due_date']).dt.date
df['date_requested'] = pd.to_datetime(df['date_requested']).dt.date
df['diff'] = (df['date_requested']-df['due_date']).dt.days

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.H4('BI Requests'),
    html.Label('Email'),
    dcc.Input(value='', type='email', autoFocus=True, inputMode='email', id='enter_email'),
    html.Label('Request Title'),
    dcc.Input(value='', type='text', id='enter_title'),
    html.Label('Request Details'),
    dcc.Input(value='', type='text', id='enter_details'),
    html.Label('Due Date'),
    dcc.DatePickerSingle(id='enter_due_date'),
    html.Br(),
    html.Br(),
    html.Button('Submit', id='submit_entry'),
    html.Br(),
    html.Br(),
    #generate_table(df),
html.Div([
    dash_table.DataTable(id='data-table',
        columns=[
            {'name':'Email', 'id': 'email' , 'type':'text', 'selectable':True, 'editable':False},
            {'name':'Request Title', 'id': 'request_title' , 'type':'text', 'selectable':True, 'editable':True},
            {'name':'Request Details', 'id': 'request_details' , 'type':'text', 'selectable':True, 'editable':True},
            {'name':'Due', 'id': 'due_date' , 'type':'datetime', 'selectable':True, 'editable':True},
            {'name':'Requested', 'id': 'date_requested' , 'type':'datetime', 'selectable':True, 'editable':False},
            {'name':'Diff', 'id': 'diff' , 'type':'numeric', 'selectable':True, 'editable':False}],
        style_as_list_view=True,
        style_cell={'padding': '5px', 'whiteSpace':'normal', 'height':'auto', 'textAlign':'left'},
        style_header={
                    'backgroundColor': 'navy',
                    'color': 'white',
                    'fontWeight': 'bold'},
        style_data_conditional=[
        {
            'if': {'row_index': 'odd'},
            'backgroundColor': 'rgb(248, 248, 248)'
        }, 
        {
            'if':{
                'filter_query':'{diff} < 4',
            },
            'backgroundColor':'#E6B0AA'
        },
        {
            'if':{
                'filter_query':'{diff} >=4 && {diff} < 14',
            },
            'backgroundColor':'#F9E79F'
        },
        {
            'if':{
                'filter_query':'{diff} > 14',
            },
            'backgroundColor':'#A9DFBF'
        },
    ],  
        style_data={'whiteSpace':'normal', 'height':'auto'},
        style_table={'height': '300px', 'overflowY': 'auto'},
        fixed_rows={'headers': True},
        data=df.to_dict('records'),
        editable=True,
        filter_action="native",
        sort_action="native",
        sort_mode="multi",
        row_selectable="multi",
        row_deletable=True,
        selected_columns=[],
        selected_rows=[],
        page_action="native",
        page_current= 0,
        page_size= 100,
        hidden_columns=['diff']
        )
]),
])

@app.callback(
    Output('data-table', 'data'),
    [Input('submit_entry', 'n_clicks')],
    [Input('data-table', 'derived_virtual_data')],
    [
        State('enter_email', 'value'),
        State('enter_title', 'value'),
        State('enter_details', 'value'),
        State('enter_due_date', 'date')
    ],
) 

def entry_to_db(self, submit_entry, enter_email, enter_title, enter_details, enter_due_date):   
    conn = sqlite3.connect('BI_Requests.db')
    cur = conn.cursor()

    if submit_entry:

        sample_entry = [
            {
                'email':enter_email,
                'request_title':enter_title , 
                'request_details':enter_details,
                'due_date': enter_due_date, 
                'date_requested' : dt.now()
            }
        ]
        insert_entry = cur.execute("INSERT INTO bi_requests (email, request_title, request_details, due_date, date_requested) "
                                                "VALUES (?, ?, ?, ?, ?)", (enter_email, enter_title, enter_details, enter_due_date, dt.now()), sample_entry)

        conn.commit()

        df = pd.read_sql("SELECT email, request_title, request_details, due_date, date_requested FROM bi_requests;", conn, parse_dates=['due_date','date_requested'])
        df['due_date'] = pd.to_datetime(df['due_date']).dt.date
        df['date_requested'] = pd.to_datetime(df['date_requested']).dt.date
        df['diff'] = (df['date_requested']-df['due_date']).dt.days 
        data=df.to_dict('records')

        return data

        raise dash.exceptions.PreventUpdate

if __name__ == '__main__':
    app.run_server(debug=True)
    conn.close()
1

There are 1 answers

0
coralvanda On BEST ANSWER

I think the problem is coming from the fall-through condition of your function. If the submit_entry button has not been clicked, your function will return None by default. If you move the raise dash.exceptions.PreventUpdate out one indentation level, then it will become the default behavior of the function when that button has not been clicked.

I think that should work, but every once in a while I have some trouble with PreventUpdate. If you run into that, you could always use the State of the table's data and return that as the default.