Visualizzare un messaggio di attesa durante esecuzione query

di il
9 risposte

Visualizzare un messaggio di attesa durante esecuzione query

Carissimi, sono nuovo con python e html, ma grazie ai vari suggerimenti sto andando avanti su un progettino.

Vorrei chiedervi un consiglio su come poter implementare la visualizzazione di un messaggio di attesa nel frattempo che elaboro una query.

Nello specifico sto lavorando tramite pagina html dove ho la possibilità di inserire un intervallo di date per poi eseguire la query che interrogherà il db. Visto che l'elaborazione potrebbe richiedere anche 20 secondi mi piacerebbe far visualizzare all'utente che il processo è in elaborazione anzichè vedere la pagina in attesa (l'ideale sarebbe una barra di progressione)…. Non so dove posso intercettare l'evento…

al momento lavoro tramite

@app.route('/',methods=['GET', 'POST'])
def index(result=None):  

return render_template('pagina.html', variabile1….variabile2…)

Grazie mille!!

9 Risposte

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    02/08/2023 - SunnyBear ha scritto:


    Vorrei chiedervi un consiglio su come poter implementare la visualizzazione di un messaggio di attesa nel frattempo che elaboro una query.

    Questo devi implementarlo all'interno della pagina Web stessa, usando HTML e soprattutto JavaScript.

    Quando invochi la tua Web API scritta in Python, usando la Fetch API (o equivalente), mostri un elemento della pagina che funga da “loader” e visualizzi una animazione di qualche tipo, in attesa che il server ti restituisca la risposta.

    Nel momento in cui giunge la risposta, la visualizzi nella pagina e contemporaneamente rimuovi/nascondi il “loader” di prima.

    Dai un'occhiata a questo tutorial su W3CSchool per uno spunto, ma facendo ricerche ne trovi a bizzeffe.

    In linea di massima, al netto di ottimizzare la query per impiegare meno tempo possibile nell'esecuzione, lato Python direi che non devi fare nulla di particolare: l'azione si svolge tutta nel client, ossia nel browser, a meno di non voler implementare altri meccanismi più complessi (lazy loading, ecc.).

    Ciao! :)

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    Grazie Alka, per l'ennesimo suggerimento…! Sto imparando tanto su questo nuovo linguaggio..

    Sinceramente avevo pensato di giocare con delle chiamate a relative pagine web tramite metodo GET e POST, ma alla fine non avendo basi solide mi sono incartato…

    Sto provando a studiare le indicazioni in merito alla Fetch API e all'oggetto loader. Mentre per quest'ultimo non ho avuto problemi a comprenderne il funzionamento, con la Fetch mi sto perdendo un pochino… sto trovando tante informazioni e temo di aver fatto tanta confusione in testa… probabilmente uso dei metodi errati e di conseguenza anche risultati poco ottimizzati… 

    Provo a riepilogare cosa faccio…

    Il mio file APP.PY al momento è in grado di ricevere i parametri inseriti nella pagina INDEX.HTML (un intervallo di date) ed in base a queste informazioni, una volta creata la connessione al server SQL, genera ed esegue la query. Poi creo in cursore ed eseguo la query tramite classico cursor.execute(query)  poi con un ciclo for butto tutto su un vettore tramite for row in cursor.fetchall(): e il tutto alla fine viene restituito alla pagina html tramite render_template.

    Il file INDEX.HTML come dicevo contiene 2 oggetti per selezionare l'intervallo di date e poi tramite una classe="accordion" visualizzo il risultato tramite ciclo for facendo riferimento al vettore inviato dal render_template.

    Spero che la logica utilizzata fin qui sia corretta e che non faccio già strani giri con i dati in possesso…

    Poi il mio dubbio rimane dove intercettare l'attesa della query… perchè nella mia testa dovrei intercettarla sul file APP.PY quando eseguo la query… ma Alka parla di lavorare su html con javascript… 

    Chiedo scusa in anticipo per la mia confusione mentale, ma sto imparando 2 linguaggi nuovi  (Python e HTML) a me completamente lontani venendo da VisualBasic…

    Qualsiasi suggerimento sarà apprezzato!!

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    04/09/2023 - SunnyBear ha scritto:


    Spero che la logica utilizzata fin qui sia corretta e che non faccio già strani giri con i dati in possesso…

    Difficile fare valutazioni senza vedere il codice, soprattutto perché usi in termini impropri ("oggetti" al posto di campi, visualizzazioni tramite classe, ecc.).

    Bisogna vedere nel dettaglio come hai implementato il tutto, anche se non ho ancora capito bene qual è il problema (se c'è).

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    Hai ragione… per oggetti intendevo in maniera grossolana un campo data con possibilità di apertura calendario….

    Giro i due codici così da rendere tutto più chiaro… 

    File APP.PY

    from flask import Flask, render_template, request
    
    
    import pyodbc, calendar, datetime, locale
    from datetime import date, datetime, timedelta
    from gevent.pywsgi import WSGIServer
    
    
    app = Flask(__name__,template_folder='c:\\sito\\templates' )
    
    f = open("AHR.TXT", "r")#leggo parametri da file
    IP_APP=f.readline()[:-1]
    
    
    @app.route('/',methods=['GET', 'POST'])
    def index(result=None):  
       
    
        Variabile_DA= request.args.get('DA',None)
        Variabile_A= request.args.get('A',None)
        
        #calcola GIORNO, MESE ED ANNO CORRENTE
        MESENOW=(datetime.now()- timedelta(days=60)).strftime('%m')
        ANNONOW=(datetime.now()- timedelta(days=60)).strftime('%Y')
        GIORNONOW=(datetime.now()-timedelta(days=60)).strftime('%d')
    
     
        if not Variabile_DA:  
            Variabile_DA="{d '"+ANNONOW +"-" + MESENOW+ "-01'}"
            Variabile_A="{d '"+ANNONOW +"-" + MESENOW+ "-" + GIORNONOW +"'}"
        else: 
            Variabile_DA="{d '" + Variabile_DA + "'}"
            Variabile_A="{d '" + Variabile_A + "'}"
    
     
        
        f = open("AHR.TXT", "r")#leggo parametri da file
        IP_APP=f.readline()[:-1]
        SERVERSQL=f.readline()[:-1]
        DATABASESQL=f.readline()[:-1]
        USER=f.readline()[:-1]
        PASSWORD=f.readline()[:-1]
        AZIENDA=f.readline()#su ultima riga non cancello carattere di ritorno a capo    
        
        f.close()
            
        connection_string = "DRIVER={ODBC Driver 17 for SQL Server};SERVER="+ SERVERSQL+";DATABASE="+DATABASESQL+";UID="+USER+";PWD="+PASSWORD
        cnn = pyodbc.connect(connection_string)
        
        
        query=f"select CERE2KVC.RSDATREG,CERE2KVC.RSPUNVEN,PUN_VEND.PVDESCRI,CERE2KVC.RPTOTCON-CERE1KVC.RPRESTO as RPTOTCON,CERE2KVC.RPVALASS,CERE2KVC.RPVALCCR,CERE2KVC.RPVALBUP,CERE2KVC.RPVALBUO,CERE2KVC.RPVALCRE,CERE2KVC.RPVALALT,CERE2KVC.RSINCASS-CERE1KVC.RPRESTO as RSINCASS from (((select MSC_MAST.RSDATREG,MSC_MAST.RSPUNVEN,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='01' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPTOTCON,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='02' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALASS,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='03' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALCCR,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='04' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALBUP,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='05' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALBUO,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='06' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALCRE,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND MSC_DETT.RSCODICE='99' THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RPVALALT,SUM(CASE  WHEN  MSC_DETT.RSTIPREC='P' AND(MSC_DETT.RSCODICE='01' OR MSC_DETT.RSCODICE='02' OR MSC_DETT.RSCODICE='03' OR MSC_DETT.RSCODICE='04' OR MSC_DETT.RSCODICE='05' OR MSC_DETT.RSCODICE='06' OR MSC_DETT.RSCODICE='99') THEN  MSC_DETT.RSIMPRIG ELSE  0 END) as RSINCASS from ({AZIENDA}MSC_MAST MSC_MAST Left outer Join {AZIENDA}MSC_DETT MSC_DETT on MSC_MAST.RSSERIAL=MSC_DETT.RSSERIAL) where (MSC_MAST.RSDATREG >={Variabile_DA}  AND MSC_MAST.RSDATREG <={Variabile_A} AND MSC_MAST.RSTIPTRA = 'V' AND MSC_DETT.RSTIPREC = 'P')  group by MSC_MAST.RSDATREG,MSC_MAST.RSPUNVEN) CERE2KVC Left outer Join (select MSC_MAST.RSDATREG,MSC_MAST.RSPUNVEN,SUM(CASE  WHEN MSC_MAST.RSTIPTRA='V' THEN  MSC_MAST.RS_RESTO ELSE  0 END) as RPRESTO from {AZIENDA}MSC_MAST MSC_MAST where (MSC_MAST.RSDATREG >={Variabile_DA} AND MSC_MAST.RSDATREG <={Variabile_A} )  group by MSC_MAST.RSDATREG,MSC_MAST.RSPUNVEN) CERE1KVC on CERE2KVC.RSPUNVEN=CERE1KVC.RSPUNVEN and CERE2KVC.RSDATREG=CERE1KVC.RSDATREG) Left outer Join {AZIENDA}PUN_VEND PUN_VEND on CERE2KVC.RSPUNVEN=PUN_VEND.PVCODICE)order by 2, 1 desc"
      
        DATANOW=datetime.now()- timedelta(days=60) #150
        DATANOW= (DATANOW.strftime('%Y-%m-%d'))
        
        locale.setlocale(locale.LC_ALL, 'it_IT') # assegno nazione e lingua locale per le formattazioni degli importi in euro
        NPV=0
        nrighe=0
        vettore =[]
        vettore2=[]
        cursor = cnn.cursor()
        cursor.execute(query)
        PVCORRENTE=0
        for row in cursor.fetchall(): 
            nrighe=nrighe+1
            if PVCORRENTE!=row[1]: # PER LA PRIMA RIGA INSERISCO DATI PER INTESTAZIONE  
                vettore.append({"DATA": "DATA","PVCODICE": row[1],"PVDESCRI": "P. VENDITA",  "CREDITI": "CREDITI", "ASSEGNI": "ASSEGNI", "ALTREFORME": "ALTRE FORME", "BUONISCONTO": "B. SCONTO", "BUONIPASTO": "B. PASTO", "CONTANTI": "CONTANTI", "POS": "POS", "INCASSI": "INCASSI"})   
                PVCORRENTE=row[1]
                NPV=NPV+1  # CONTEGGIO TOTALE PUNTI VENDITA
                vettore2.append({"DATA": f"{row[0]:%d/%m/%Y}"  , "PVCODICE": row[1], "PVDESCRI": row[2], "CREDITI":"€. "+locale.format_string('%.2f', row[8], True), "ASSEGNI":"€. "+locale.format_string('%.2f', row[4], True), "ALTREFORME":"€. "+locale.format_string('%.2f', row[9], True), "BUONISCONTO":"€. "+locale.format_string('%.2f', row[7], True), "BUONIPASTO":"€. "+locale.format_string('%.2f', row[6], True), "CONTANTI":"€. "+locale.format_string('%.2f', row[3], True), "POS":"€. "+locale.format_string('%.2f', row[5], True), "INCASSI":"€. "+locale.format_string('%.2f', row[10], True) })              
            vettore.append({"DATA": f"{row[0]:%d/%m/%Y}"  , "PVCODICE": row[1], "PVDESCRI": row[2], "CREDITI":"€. "+locale.format_string('%.2f', row[8], True), "ASSEGNI":"€. "+locale.format_string('%.2f', row[4], True), "ALTREFORME":"€. "+locale.format_string('%.2f', row[9], True), "BUONISCONTO":"€. "+locale.format_string('%.2f', row[7], True), "BUONIPASTO":"€. "+locale.format_string('%.2f', row[6], True), "CONTANTI":"€. "+locale.format_string('%.2f', row[3], True), "POS":"€. "+locale.format_string('%.2f', row[5], True), "INCASSI":"€. "+ locale.format_string('%.2f', row[10], True) })  
        
        cursor.close()
        cnn.commit()
        cnn.close()
        return render_template('index.html', valori=vettore,valori2=vettore2, NPV=NPV )
    
        
      
    http_server = WSGIServer((IP_APP, 12345), app)
    http_server.serve_forever()
    

    File Index.HTML

    
    <!doctype html>
    <html lang="en">
      <head>
        <!-- Required meta tags -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- Bootstrap CSS -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap....." rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
        <title>NOMETABXX</title>
      </head>
      
      
      <body>
         <nav class="navbar navbar-expand-lg navbar-light bg-white">
            <div class="container-fluid">
                <a class="navbar-brand" href="/">
    					<img src="https://www.indirizzo.logo" alt=""  class="d-inline-block align-text-top">
    			</a>
    		</div>	
         </nav>
    
    	<form action="/elaborazione" method="post" class=m-4>
    				Seleziona Periodo:  <br>
    				<div class="row">
    				<div class="col">	<input class="form-control" style="max-width:300px;" type="date" id="Da" name="DA"   placeholder="Da.."  value="" </input> 	</div>
    				<div class="col">	<input class="form-control" style="max-width:300px;" type="date" id="A" name="A"    placeholder="A..."  value="" </input>	</div>			
    				<div class="col-auto">	<button class="btn btn-primary"  type="submit">Cerca</button>	</div>
    	
    			</div>  
    	 </form>
    	 	
    	<div class="accordion m-2" id="accordionExample">
    		Totale Punti Vendita: {{NPV}}
    		{% for Npuntovendita in valori2 %} 
    			<div class="accordion-item">
    				<h2 class="accordion-header">
    					<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-<{{Npuntovendita.PVCODICE}}>" aria-expanded="false" aria-controls="#collapse-<{{Npuntovendita.PVCODICE}}>">
    						<div class="col"> <b>	 Punto Vendita: <br>  {{Npuntovendita.PVCODICE}} 	{{Npuntovendita.PVDESCRI}}	</b></div>
    						<div class="col"> <b> Ultimo Incasso aggiornato al: {{Npuntovendita.DATA}}		</b>		</div>
    						<div class="col"> <b> {{Npuntovendita.INCASSI}}	</b>		</div>
    					</button>
    				</h2>			
    
    			{% for riga in valori %}
    				{% if riga.PVCODICE == Npuntovendita.PVCODICE %}
    					<div class="accordion-header">
    						<div id="collapse-<{{Npuntovendita.PVCODICE}}>" class="accordion-collapse collapse" data-bs-parent="#accordion-header" >
    							<div class="row g-0 text-end">
    					
    								<style>
    								@media screen and (min-width: 801px) {  div.row {    font-size: 16px; padding:1px; margin-top:2px }}
    								@media screen and (max-width: 800px) {  div.row {    font-size: 9px; padding:1px; margin-top:1px; margin-left:0; margin-right:0; border:0}}
    								@media screen and (max-width: 700px) {  div.row {    font-size: 5px; padding:1px; margin-top:2px; margin-left:0; margin-right:0; border:0}}
    								</style>							
    				
    								<div class="col text-center"> 	 			{{riga.DATA}} 			</div>
    								<div class="col-2 col-lg-2 text-center">	{{riga.PVDESCRI}} 		</div>
    								<div class="col"> 	 						{{riga.CREDITI}} 		</div>
    								<div class="col"> 	 						{{riga.ASSEGNI}}		</div>
    								<div class="col"> 	 						{{riga.ALTREFORME}}		</div>
    								<div class="col"> 	 						{{riga.BUONISCONTO}} 	</div>
    								<div class="col"> 	 						{{riga.BUONIPASTO}} 	</div>
    								<div class="col">	 						{{riga.CONTANTI}}		</div>
    								<div class="col text-end">	 				{{riga.POS}}   	    	</div>
    								<div class="col"> <b>						{{riga.INCASSI}} &nbsp </b>	</div>
    							</div>	
    						</div>
    					</div>
    				{% endif %}
    			{% endfor %}		
    			</div>
    		{% endfor %}
    	</div>
    </div>
     	<script src="https://cdn.jsdelivr.net/npm/bootstrap...t/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>
    </body>
    </html>
    

    Tutto funziona correttamente in base alle mie necessità…. L'unica cosa che volevo aggiungere è un “loader”, o meglio una barra di progressione, che durante l'esecuzione della query, dia un messaggio di attesa…visto che a volte ci vogliono anche una ventina di secondi…

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    Cito me stesso.

    02/08/2023 - Alka ha scritto:


    Questo devi implementarlo all'interno della pagina Web stessa, usando HTML e soprattutto JavaScript.

    […]

    Dai un'occhiata a questo tutorial su W3CSchool per uno spunto, ma facendo ricerche ne trovi a bizzeffe.

    Non c'è traccia di script alcuno nella tua pagina.
    Hai dato un'occhiata come suggerito?

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    Esatto non c'è traccia… Ho postato il codice dell'applicazione funzionante senza la gestione del loader. 

    Dall'esempio ho visto come funziona un loader… la mia domanda è rivolta su come intercettare il momento in cui inizia l'esecuzione della query per far partire il loader e quando fermarlo perchè la query è stata eseguita. Dall'esempio si fa tutto manualmente, parte il loader all'avvio della pagina e deve durare 3 secondi… almeno ho capito questo… :) 

    Prima parlavi di  fetch Api, suppongo devo partire da qui… 

    Ti chiedo perdono per la mia estrema ignoranza in materia… non voglio irritare nessuno… non voglio la soluzione in bocca… vorrei capire le logiche… in base al codice scritto penso che devo lavorare sul file App.py visto che la query la lancio da lì….giusto? Ma come?

    Grazie ancora per i suggerimenti…e soprattutto per la pazienza…!!!

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    04/09/2023 - SunnyBear ha scritto:


    la mia domanda è rivolta su come intercettare il momento in cui inizia l'esecuzione della query per far partire il loader e quando fermarlo perchè la query è stata eseguita.

    Ok, partiamo da questo punto. Non devi intercettare quando inizia la query e quando finisce: sei tu che mandi tramite apposita funzione (la famigerata Fetch API) una richiesta HTTP all'indirizzo al quale risponde un endpoint che esegue la query e ti restituisce i risultati.

    Non devi “intercettare”: sei tu che fai partire la query chiamando un endpoint che restituisce i dati ottenuti dalla query stessa come valore di ritorno, al posto di una pagina tradizionale.

    Prima di iniziare la chiamata, visualizzi il loader come indicato nell'esempio; quando ricevi i dati dalla chiamata, restituiti dalla logica lato server, mostri i dati nella pagina al posto giusto e nascondi di nuovo il loader. Lo stesso anche in caso di errore, per non lasciarlo a video.

    La alternativa è quella di usare uno script per mostrare il loader e poi navighi verso la pagina dei risultati, ma se l'operazione è veloce, vedrai scomparire tutto e apparire dopo un po' di tempo la nuova pagina… in breve, via scripting usando JavaScript è la soluzione più indicata, ma devi documentarti meglio sulla programmazione JS all'interno del browser.

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    Ok, grazie Alka…. comincio a vedere luce in fondo al tunnel… Adesso comincio a comprendere le logiche che ci stanno dietro !

    Devo procedere nell'addentrarmi nelle Fetch API … da qualche giorno che faccio ricerche sull'argomento e sinceramente è uscito di tutto, anche perché il termine Fetch si presta a tantissime cose… Se hai qualche suggerimento su come restringere le mie ricerche da applicare al mio contesto te ne sarei grato…! Ma riconosco che già così mi hai dato una grande mano a capire meglio! Grazie ALKA !!! 

  • Re: Visualizzare un messaggio di attesa durante esecuzione query

    05/09/2023 - SunnyBear ha scritto:


    Devo procedere nell'addentrarmi nelle Fetch API …

    E' una “banale” funzione JavaScript, nulla di più.

    05/09/2023 - SunnyBear ha scritto:


    Se hai qualche suggerimento su come restringere le mie ricerche […]

    Nella mia prima risposta avevo riportato un link diretto alla documentazione: la Fetch API è quella, tutti gli altri “fetch” non c'entrano. :)

Devi accedere o registrarti per scrivere nel forum
9 risposte