I create a Dash DataTable that updates the rows of the table based on a period of time retrieved via a datetimepicker, but the resulting rows are returned as blank rows, as shown here:
What could be causing that the resulting rows are being displayed in blank?
Here is my code:
# Importa las librerías necesarias para la encripción de datos
from hmac import new
from hashlib import md5
Importa la librerías necesarias para realizar consultas web
from requests import get, post
Importa la librería necesaria para manipular objetos de tipo fecha-tiempo
from datetime import datetime, timedelta
Importa la librería necesaría para manipular datos
from pandas import read_json
Importa las librerías necesarias para crear una web app de tipo dashboard para visualización de datos
from dash import Dash
from dash.dependencies import Input, Output
from dash_html_components import Div, H2, Img
from dash_core_components import Dropdown, DatePickerRange
from dash_table import DataTable
crea las variables necesarias para conectarse al servicio web de future time
url = ‘https://someurl.com/someapiv2/system/LoginUser’
usr = ‘user’
pwd = ‘password’
pwdh = pwd.encode()
ts = str(datetime.utcnow().strftime(’%Y-%m-%d %H:%M:%S’)) # ; del datetime
msg = (usr + pwd + ts).encode()
crea la firma hash HMAC MD5 utilizando la contraseña como llave y la guarda en la variable digest
digest = new(pwdh, msg, md5).hexdigest()
Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {‘LoginName’: usr,
‘Signature’: digest,
‘TimeStamp’: ts}
Establece la conexión al web service, utiliza el recurso /System/LoginUser y autentica al usuario,
guarda en la variable r el resultado de la conexión.
r = post(url, arg)
Obtiene el UserID
UserId = str(r.json()[‘Result’][11:13])
Crea las variable necesarias para consumir el servicio de Working Day
url = ‘https://someurl.net/someapiv2/WorkingDay/Get’
Keywords = ‘’
StartDate = str((datetime.today() - timedelta(1)).strftime(’%Y-%m-%d’)) + ’ 00:00:00’
EndDate = str((datetime.today() - timedelta(1)).strftime(’%Y-%m-%d’)) + ’ 23:59:59’
Filter = ‘todos’
OrderBy = ‘’
Construye el nuevo mensaje a ser firmado
msg = (Keywords + StartDate + EndDate + Filter + OrderBy + UserId).encode()
Crea la firma hash HMAC MD5
digest = new(pwdh, msg, md5).hexdigest() # ; del new, pwdh, msg, md5
Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {‘Keywords’: ‘’,
‘StartDate’: StartDate,
‘EndDate’: EndDate,
‘Filter’: Filter,
‘OrderBy’: ‘’,
‘UserID’: UserId,
‘Signature’: digest} # ; del Keywords, StartDate, EndDate, Filter, OrderBy, UserId, digest
Invoca mediante get el recurso /WorkingDay/Get
r = get(url, arg) # ; del url, arg
Convierte la cadena json del webservice a dataframe de pandas
df = read_json(r.json()[‘Result’]) # ; del r; read_json
Filtra las columnas necesarias para el reporte de faltas injustificadas
df = df.filter(items=[‘ExportId’, ‘Name’, ‘OU5’, ‘Date’, ‘TimeGroup’, ‘Exceptions’])
Renombra las columnas del reporte
df.columns = [‘Código de empleado’, ‘Nombre del empleado’,
‘Departamento’, ‘Fecha’, ‘Horario’, ‘Excepción’]
Inicializa la aplicación web
app = Dash(‘BI-UYEDA’)
Define las hojas de estilos externas a utilizar
external_css = [
“https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css”, # Normalize the CSS
“https://fonts.googleapis.com/css?family=Open+Sans|Roboto”, # Fonts
“https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css”,
“https://cdn.rawgit.com/TahiriNadia/styles/faf8c1c3/stylesheet.css”,
“https://cdn.rawgit.com/TahiriNadia/styles/b1026938/custum-styles_phyloapp.css”
]
Añade las hojas de estilos a la aplicación
for css in external_css:
app.css.append_css({“external_url”: css})
server = app.server
Define la estructura de la aplicación
app.layout = Div([
Div([
H2(“Inteligencia de negocios UYEDA”),
Img(src=“http://someurl.mx/common/images/some_logo_img.png”)],
className=“banner”),
Div([
Div([
], style={
‘margin’: ‘5px’,
‘text-align’: ‘center’,
‘vertical-align’: ‘middle’,
‘width’: ‘48%’,
‘display’: ‘inline-block’
}),
Div([
DatePickerRange(
id=‘fechas’,
start_date=str((datetime.today() - timedelta(1)).strftime(’%Y-%m-%d’)),
end_date=str((datetime.today() - timedelta(1)).strftime(’%Y-%m-%d’)),
display_format=‘DD/MM/YYYY’,
max_date_allowed=str((datetime.today() - timedelta(1)).strftime(’%Y-%m-%d’)),
min_date_allowed=‘2018/01/01’
),
], style={
‘margin’: ‘5px’,
‘text-align’: ‘center’,
‘vertical-align’: ‘middle’,
‘width’: ‘48%’,
‘display’: ‘inline-block’
})
],
className="container"
),
Div([
DataTable(id='table',
columns=[{'name': i, 'id': i} for i in df.columns],
data=[{}], #df.to_dict('rows'),
sorting=True,
style_table={'overflowX': 'scroll'},
style_cell={'minWidth': '0px',
'maxWidth': '180px',
'whiteSpace': 'normal'},
css=[{
'selector': '.dash-cell div.dash-cell-value',
'rule': 'display: inline; white-space: inherit; overflow: inherit; text-overflow: inherit;'
}],
virtualization=True,
pagination_mode=True,
n_fixed_rows=1,
merge_duplicate_headers=True
)
],
className="container")
])
Crea las llamadas a la aplicación para actualizar las filas
@app.callback(
Output(‘table’, ‘data’),
[Input(‘fechas’, ‘start_date’),
Input(‘fechas’, ‘end_date’)]
)
Crea la función que actualiza las filas de la tabla
def act_filas(start_date, end_date):
“”"
Esta función actualiza las filas de un datatable
:param start_date: Cadena de caracteres que indica la fecha inicial del reporte
:param end_date: Cadena de caracteres que indica la fehca final del reporte
:return: Retorna las filas que actualizaran las filas del datatable
“”"
# crea las variables necesarias para conectarse al servicio web de future time
url = ‘https://someurl.net/someapiv2/system/LoginUser’
usr = ‘user’
pwd = ‘password’
pwdh = pwd.encode()
ts = str(datetime.utcnow().strftime(’%Y-%m-%d %H:%M:%S’)) # ; del datetime
msg = (usr + pwd + ts).encode()
# crea la firma hash HMAC MD5 utilizando la contraseña como llave y la guarda en la variable digest
digest = new(pwdh, msg, md5).hexdigest()
# Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {'LoginName': usr,
'Signature': digest,
'TimeStamp': ts}
# Establece la conexión al web service, utiliza el recurso /System/LoginUser y autentica al usuario,
# guarda en la variable r el resultado de la conexión.
r = post(url, arg)
# Obtiene el UserID
UserId = str(r.json()['Result'][11:13])
# Crea las variable necesarias para consumir el servicio de Working Day
url = 'https://someurl.net/someapiv2/WorkingDay/Get'
Keywords = ''
StartDate = start_date + ' 00:00:00'
EndDate = end_date + ' 23:59:59'
Filter = 'todos'
OrderBy = ''
# Construye el nuevo mensaje a ser firmado
msg = (Keywords + StartDate + EndDate + Filter + OrderBy + UserId).encode()
# Crea la firma hash HMAC MD5
digest = new(pwdh, msg, md5).hexdigest() # ; del new, pwdh, msg, md5
# Crea los argumentos necesarios para acceder al webservice y los asigna a la variable argumentos
arg = {'Keywords': '',
'StartDate': StartDate,
'EndDate': EndDate,
'Filter': Filter,
'OrderBy': '',
'UserID': UserId,
'Signature': digest} # ; del Keywords, StartDate, EndDate, Filter, OrderBy, UserId, digest
# Invoca mediante get el recurso /WorkingDay/Get
r = get(url, arg) # ; del url, arg
# Convierte la cadena json del webservice a dataframe de pandas
df = read_json(r.json()['Result'])
# Reemplaza los valores nulos por caracter vacio
df.fillna('', None, None, True)
# Descarta los registros correspondientes a practicantes, del cómputo de faltas
df.drop(df[df['TimeGroup'] == 'Practicantes'].index, inplace=True)
# Descarta los registros correspondientes a horarios libres, del cómputo de faltas
df.drop(df[df['TimeGroup'] == 'Libre'].index, inplace=True)
# Descarta los registros correspondientes a descansos, del cómputo de faltas
df.drop(df[df['ProjectedTimeToWork'].str.contains('00:00:00')].index, inplace=True)
# Descarta los registros correspondientes a trabajadores borrados, del cómputo de faltas
df.drop(df[df['Name'].str.contains('Borrado')].index, inplace=True)
# Descarta los registros correspondientes a visitantes, del cómputo de faltas
df.drop(df[df['Name'].str.contains('Visitante')].index, inplace=True)
# Descarta los registros correspondientes a personal directivo, del cómputo de faltas
df.drop(df[df['Name'].str.contains('Director')].index, inplace=True)
# Descarta los registros correspondientes a trabajadores borrados, del cómputo de faltas
df.drop(df[df['Name'].str.contains('New node')].index, inplace=True)
# Descarta los registros correspondientes a personal de soporte y pruebas, del cómputo de faltas
df.drop(df[df['Name'].str.contains('Soporte y Pruebas')].index, inplace=True)
# Descarta los registros correspondientes a Incapacidad IMSS Riesgo de Trabajo, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('[057]')].index, inplace=True)
# Descarta los registros correspondientes a permiso sin goce de sueldo 069, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('Permiso Sin Goce de Sueldo')].index, inplace=True)
# Descarta los registros correspondientes a Día de castigo 069, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('Día de castigo')].index, inplace=True)
# Descarta los registros correspondientes a vacaciones, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('[801]')].index, inplace=True)
# Descarta los registros correspondientes a falta con goce de sueldo 800, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('falta con goce de sueldo')].index, inplace=True)
# Descarta los registros correspondientes a dias feriados, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('Dia No Laborable General de Ley día feriado')].index, inplace=True)
# Descarta los registros correspondientes a Incapacidad IMSS Enfermedad General 060, del cómputo de faltas
df.drop(df[df['Exceptions'].str.contains('Incapacidad IMSS Enfermedad General')].index, inplace=True)
# Descarta los registros correspondientes a omisión de registro de entrada
df.drop(df[df['InHour'].str[11:16] > '00:00'].index, inplace=True)
# Filtra las columnas necesarias para el reporte de faltas injustificadas
df = df.filter(items=['ExportId', 'Name', 'OU5', 'Date', 'TimeGroup', 'Exceptions'])
# Renombra las columnas del reporte
df.columns = ['Código de empleado', 'Nombre del empleado',
'Departamento', 'Fecha', 'Horario', 'Excepción']
# Envía los resultados del DataFrame a las filas del data table
data = [{'name': i, 'id': i} for i in df.to_dict('rows')]
# Retorna los registros para actualizar la tabla
return data
if name == ‘main’:
app.run_server(debug=True)