Hello, I am trying to make a multi page app in dash, which get and modifies data in mongodb. While I run the app I get an ‘NoneType’ object is not callable , I think it’s because of the
cc variable in the @dash.clientside_callback ( Admin.py). Any help would be highly appreciated
App.py
import dash
from dash import html, dcc
import dash_bootstrap_components as dbc
app = dash.Dash(__name__, use_pages=True,suppress_callback_exceptions=True)
app.layout = html.Div(
[
# main app framework
html.Div("Admin Page", style={'fontSize':50, 'textAlign':'center'}),
html.Div([
dcc.Link(page['name']+" | ", href=page['path'])
for page in dash.page_registry.values()
]),
html.Hr(),
# content of each page
dash.page_container
]
)
if __name__ == "__main__":
app.run(debug=True)
Admin.py
import dash
from dash import html, dcc, Input, Output, State, dash_table
import pandas as pd
import plotly.express as px
import pymongo
from bson.objectid import ObjectId
import dash_bootstrap_components as dbc
client = pymongo.MongoClient("mongodb+srv://HARSHA:123@cargoshipmanagementsyst.kgitmho.mongodb.net/?retryWrites=true&w=majority")
db = client["cargo"]
collection = db["Billing"]
dash.register_page(__name__,path='/')
layout = html.Div(children = [
html.H1('ADMIN PAGE', style={'textAlign': 'center'}),
# interval activated once/week or when page refreshed
dcc.Interval(id='interval_db', interval=86400000 * 7, n_intervals=0),
html.Div(id='mongo-datatable', children=[]),
html.Div([
html.Div(id='pie-graph', className='five columns'),
html.Div(id='hist-graph', className='six columns'),
], className='row'),
dcc.Store(id='changed-cell')
])
# Display Datatable with data from Mongo database
@dash.callback(Output('mongo-datatable', component_property='children'),
Input('interval_db', component_property='n_intervals')
)
def populate_datatable(n_intervals):
# Convert the Collection (table) date to a pandas DataFrame
df = pd.DataFrame(list(collection.find()))
# Convert id from ObjectId to string so it can be read by DataTable
df['_id'] = df['_id'].astype(str)
print(df.head(20))
return [
dash_table.DataTable(
id='our-table',
data=df.to_dict('records'),
columns=[{'id': p, 'name': p, 'editable': False} if p == '_id'
else {'id': p, 'name': p, 'editable': True}
for p in df],
),
]
# store the row id and column id of the cell that was updated
@dash.clientside_callback(
"""
function (input,oldinput) {
if (oldinput != null) {
if(JSON.stringify(input) != JSON.stringify(oldinput)) {
for (i in Object.keys(input)) {
newArray = Object.values(input[i])
oldArray = Object.values(oldinput[i])
if (JSON.stringify(newArray) != JSON.stringify(oldArray)) {
entNew = Object.entries(input[i])
entOld = Object.entries(oldinput[i])
for (const j in entNew) {
if (entNew[j][1] != entOld[j][1]) {
changeRef = [i, entNew[j][0]]
break
}
}
}
}
}
return changeRef
}
}
""",
Output('changed-cell', 'data'),
Input('our-table', 'data'),
State('our-table', 'data_previous')
)
# Update MongoDB and create the graphs
@dash.callback(
Output("pie-graph", "children"),
Output("hist-graph", "children"),
Input("changed-cell", "data"),
Input("our-table", "data"),
)
def update_d(cc,tabledata):
if not cc:
# Build the Plots
pie_fig = px.pie(tabledata, values='No Of Containers', names='Container Type')
hist_fig = px.bar(tabledata, x='Dimensions', y='Amount')
else:
print(f'changed cell: {cc}')
print(f'Current DataTable: {tabledata}')
x = int(cc[0])
# update the external MongoDB
row_id = tabledata[x]['Order_id']
col_id = cc[1]
new_cell_data = tabledata[x][col_id]
collection.update_one({'Order_id': row_id},
{"$set": {col_id: new_cell_data}})
# Operations guide - https://docs.mongodb.com/manual/crud/#update-operations
pie_fig = px.pie(tabledata, values='No Of Containers', names='Container Type')
hist_fig = px.px.bar(tabledata, x='Dimensions', y='Amount')
return dcc.Graph(figure=pie_fig), dcc.Graph(figure=hist_fig)