Firebase: come integrare un database real-time in Python

Firebase è un prodotto di Google Cloud che può. essere utilizzato per costruire applicazioni web in modo semplice e veloce. Tra le sue funzionalità vi è la possibilità di creare un database NoSQL realtime. Scopriamo come interagire con il database in un programma python.

Share

Reading time: 8 minutes

Firebase è una piattaforma serverless per lo sviluppo di applicazioni mobili e web.

Open source ma supportata da Google, Firebase sfrutta l’infrastruttura di Google e il suo cloud per fornire una suite di strumenti per scrivere, analizzare e mantenere applicazioni cross-platform. Firebase, infatti, offre funzionalità come analisi, database (usando strutture noSQL), messaggistica e segnalazione di arresti anomali per la gestione di applicazioni web, iOS e Android.

In questo articolo affronteremo come sfruttare il database NoSQL messo a disposizione all’interno di un programma python.

Creazione del database

Per usare Firebase dovremo prima creare un progetto. Per farlo, andate su console.firebase.google.com e cliccate su “Aggiungi progetto”. Inserite il nome e decide se abilitare Google Analytics per il progetto (essendo un esempio lo abbiamo disabilitato, ma lo raccomandiamo). Una volta che il progetto è creato vi verrà mostrata la seguente pagina.

Per prima cosa, creeremo un database in tempo reale e per farlo, cliccate su “Creazione” nel pannello di sinistra e poi su “Realtime Database”. Nella pagina successiva, selezionate “Crea database”. Per prima cosa è necessario selezionare la posizione del database, a discrezione dell’utente. Per ridurre al minimo le latenze di rete, scegliete sempre una regione che è più vicina al server dove girerà la vostra applicazione e/o dove la maggior parte degli utenti si collegheranno.

Successivamente è necessario impostare le regole di sicurezza. Si tratta di una parte molto importante della gestione del database, in quanto determinerà l’accesso degli utenti al database. Poiché si tratta di un progetto di prova, si può selezionare “Avvia in modalità di prova” (successivamente lo modificheremo) e fare clic su “Attiva”. A questo punto, si dovrebbe essere reindirizzati a una pagina come questa.

Il vostro database è stato creato e pronto all’utilizzo! È stato semplicissimo, non è vero?!?

Vi vogliamo solo far notare un paio di cose prima di procedere. L’URL che vedete al centro è l’indirizzo del vostro database. Poiché abbiamo impostato le regole del nostro database in modo che possano essere lette e scritte da tutti, ciò significa che chiunque abbia quell’URL può visualizzare e modificare il vostro database. Quindi è una buona idea tenere questo URL per sé, anche se si hanno regole più restrittive.

A questo proposito, se si naviga nella scheda delle regole, si vedrà quanto segue

				
					{
  "rules": {
    ".read": "now < 1683756000000",  // 2023-5-11
    ".write": "now < 1683756000000",  // 2023-5-11
  }
}
				
			

Questa è probabilmente una delle caratteristiche più importanti da tenere in considerazione, perché determina il modo in cui si accede al database. In questo momento abbiamo entrambe le proprietà .read e .write codificate a true, il che rende il nostro database molto insicuro, perché chiunque abbia l’URL potrebbe apportarvi qualsiasi tipo di modifica. Per ora lo lasceremo così, perché sarà più facile da testare, ma più avanti vi mostreremo come si può implementare un livello di sicurezza maggiore.

Integrazione in Python

La prima cosa da fare è ottenere un riferimento al database nel nostro script Python. Per farlo, dovete tornare alla pagina “Panoramica del progetto” e nella schermata centrale dovreste vedere questa icona. Cliccateci sopra.

Date quindi un nome all’applicazione (che non ha molta importanza) e premere “Registra”. Verrà quindi visualizzata una schermata come questa.

Copiate il contenuto della variabile firebaseConfig.

Attenzione

Queste informazioni sono SENSIBILI, quindi assicuratevi di non condividerle.

Queste variabili saranno utilizzate per configurare il database dal vostro script. Se non avete ancora creato uno script Python, createlo ora e aggiungete il contenuto della variabile firebaseConfig che avete appena copiato alla variabile Python config. Poiché il codice copiato non è in Python, non dimenticate di aggiungere le virgolette alle chiavi.

Ora possiamo creare un riferimento al nostro database e per farlo useremo il pacchetto Pyrebase. Se non lo avete ancora installato, assicuratevi di eseguire prima pip install pyrebase4.

				
					import pyrebase

config = {...}

firebase = pyrebase.initialize_app(config)
database = firebase.database()
				
			

Ora possiamo accedere al database ed effettuare alcune operazioni di base, dette anche CRUD (Create, Read, Update, Delete).

Creare documenti

 

La prima operazione che utilizzeremo sarà la Create, poiché vogliamo inviare dei dati al nostro database. Si tratta di un processo molto semplice: prima si crea un json con i dati che si vogliono inviare e poi si inviano i dati! In questo modo:

				
					database = firebase.database()

data = {'name': 'Alessandro', 'age': 40, 'likes_python': True}
database.push(data)

				
			

Se si esegue questo codice, si avrà una voce nel database come riportato di seguito

Si noti che non è necessario specificare alcuna struttura predefinita per i dati, purché li si invii in un formato json valido. L’esecuzione è velocissima ed è per questo motivo che si chiama Realtime Database.

Si può anche notare che i dati sono memorizzati sotto quella che sembra essere una stringa casuale. È il modo con cui Firebase identifica in modo univoco chi ha effettuato la richiesta. Se si esegue nuovamente lo stesso codice, si genererà una nuova voce con un id simile.

Ma cosa succede se vogliamo dare un id specifico ai dati che inviamo? Invece di usare la funzione push(data), dobbiamo usare la funzione set(data). Tuttavia, se eseguiamo di nuovo lo stesso codice, sostituendo solo il nome della funzione, vediamo che ora i nostri dati non fanno parte di alcuna struttura, il che non è ideale.

Per risolvere questo problema, dobbiamo assegnargli manualmente un id. Per far ciò modifichiamo il codice come riportato di seguito.

				
					database = firebase.database()

data = {'name': Alessandro, 'age': 25, 'likes_python': True}
userId = '123456'
database.child(userId).set(data)
				
			

Se eseguiamo questo codice, vedremo che ora i nostri dati sono memorizzati in una “cartella” con l’id specificato. Il comando child aggiunge fondamentalmente una cartella al database. Se si vuole, si possono creare tutte le cartelle annidate che si vogliono, aggiungendo la funzione child.

Idealmente, l’ID utente che abbiamo codificato dovrebbe essere qualcosa di individuale per ogni utente, ma lo vedremo più avanti.

Aggiornamento

Supponiamo che un utente si autentichi nella vostra applicazione e aggiorni il suo nome. Si potrebbe sempre ottenere l’informazione corrente, aggiornare il campo desiderato e inviare nuovamente l’informazione. Ma questo non sembra molto pratico! Usiamo, invece, la funzione update e passiamo i campi che vogliamo modificare e i loro valori, in questo modo:

				
					database = firebase.database()
userId = '123456'
# Data we previously sent
# data = {'name': Alessandro, 'age': 40, 'likes_python': True}
# database.child('users').child(userId).set(data)

database.child('users').child(userId).update({'name': 'Mario'})
				
			

Dopo aver eseguito questo codice, possiamo vedere che le informazioni sull’utente sono state aggiornate.

Leggere e cancellare

Le due funzionalità rimanenti sono molto semplici. Per leggere le informazioni dal database, possiamo usare la funzione get. Per esempio, supponiamo di voler recuperare le informazioni dell’utente appena creato.

				
					user_info = database.child('users').child(userId).get()
print(user_info.val())
				
			

Otterremo il seguente output:

				
					OrderedDict([('age', 40), ('likes_python', True), ('name', 'Mario')])
				
			

Supponiamo che si vogliano ottenere le informazioni da tutti gli utenti, si può fare così

				
					data = {"name": "Luigi", "age": 40, "likes_python": False}
database.child('users').child(userId).set(data)
users_info = database.child('users').get()
print(users_info.val())
				
			

Otterremo, pertanto, il seguente risultato:

				
					OrderedDict([('123456', {'age': 40, 'likes_python': True, 'name': 'Mario'}), ('654321', {'age': 30, 'likes_python': False, 'name': 'Luigi'})])
				
			

Tenete presente che siamo in grado di farlo, grazie alle regole che abbiamo definito. Di solito, un determinato utente non può accedere all’intero database, ma poiché abbiamo impostato la proprietà .read su True, questo è possibile.

Infine, per quanto riguarda l’azione Delete, è possibile utilizzare la funzione remove.

				
					userId = '654321'
database.child('users').child(userId).remove()
users_info = database.child('users').get()
print(users_info.val())
				
			

A questo punto riavremo solo un documento ritornato

				
					OrderedDict([('123456', {'age': 40, 'likes_python': True, 'name': 'Mario'})])
				
			

Questo è praticamente tutto per quanto riguarda le operazioni di base che si possono fare con Pyrebase, probabilmente avrete bisogno solo di queste 4 per eseguire un’applicazione solida.

Sicurezza

L’ultima cosa che vogliamo trattare è come rendere il database più sicuro. È estremamente sconsigliato distribuire l’applicazione con le regole come abbiamo impostato all’inizio. Questo è un argomento importante e potete trovare maggiori informazioni nella documentazione. Per semplificare, aggiorniamo le nostre regole con le seguenti:

				
					{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}
				
			

Il codice sopra riportato consente la lettura e la scrittura solo agli utenti autenticati. Questo significa che anche se qualcuno ottiene l’accesso alla configurazione, dovrà comunque essere loggato per poter effettuare qualsiasi modifica.

A questo proposito, non abbiamo ancora parlato di autenticazione, ma dato che ora richiederemo che l’utente sia autenticato, per poter accedere al database, implementiamola.

Si noti che non è necessario che un utente sia autenticato per poter utilizzare l’applicazione, ma se questo è il caso, in base alle regole di cui sopra, quell’utente non potrà aggiornare il proprio profilo, o meglio, voi, in quanto proprietari dell’applicazione, non potrete aggiornare il profilo di quell’utente per suo conto, perdendo così informazioni preziose.

Per impostare un sistema di autenticazione, andate nella “Panoramica del progetto” nella console di Firebase e nel pannello di sinistra, alla voce “Creazione”, selezionate “Authentication” e poi fate clic su “Inizia”. Verrà quindi visualizzata una schermata in cui è possibile scegliere tra un’ampia gamma di provider di accesso; tuttavia, a scopo di test, selezionare il provider “Email/Password”.

Dopo averla abilitata, dovreste essere in grado di navigare nella scheda Utenti, che sarà vuota in quanto non abbiamo ancora aggiunto alcun utente. Il modo abituale di aggiungere un utente è lasciare che sia lui stesso a creare un account, quindi l’ideale sarebbe implementare un sistema di login/sign in nella vostra applicazione, ma per dimostrare come il sistema funziona ci limiteremo a creare un utente direttamente dalla console. Per farlo, fare clic su “Aggiungi utente” e poi scegliere un’e-mail e una password. Non è necessario che sia un’e-mail valida e assicuratevi di copiare la password, perché una volta creato l’utente, non sarà più possibile accedervi. Dopo aver creato l’utente, avrete una nuova voce nella tabella degli utenti.

Ok, ora, prima di implementare la parte di autenticazione dal lato dell’applicazione, vediamo cosa succede se proviamo a eseguire un semplice set

				
					userId = '654321'
data = {"name": "Luigi", "age": 30, "likes_python": False}
database.child('users').child(userId).set(data)
				
			

Viene sollevato il seguente errore

				
					raise HTTPError(e, request_object.text)
requests.exceptions.HTTPError: [Errno 401 Client Error: Unauthorized for url: https://sampleproject-ebe7b-default-rtdb.europe-west1.firebasedatabase.app/users/654321.json] {
  "error" : "Permission denied"
}
				
			

Come si può vedere, si ottiene un errore “Permesso negato”, il che significa che l’utente corrente non ha il permesso di aggiornare quella parte del database. Ora facciamo il “login” dell’utente (cioè digitiamo l’e-mail e la password) e proviamo a fare la stessa richiesta.

				
					firebase = pyrebase.initialize_app(config)
database = firebase.database()
auth = firebase.auth()
email = ‘alessandro.fiori@flowygo.com'
password = '123456'
try:
    user = auth.sign_in_with_email_and_password(email, password)
    userId = '654321'
    data = {"name": "Luigi", "age": 30, "likes_python": False}
    database.child('users').child(userId).set(data, user['idToken'])
    print("logged in")
except:
    print("failed to log in")
				
			

Se si esegue questo codice, non si otterrà alcun errore e si può verificare che l’utente è stato effettivamente aggiunto al database! La differenza è che stiamo inviando la richiesta di set con la variabile user[‘idToken’] che abbiamo ottenuto dal log in. Anche in questo caso, non è il modo ideale, perché l’ideale sarebbe che l’utente inserisse le proprie credenziali, ma è solamente una dimostrazione.

More To Explore

Intelligenza artificiale

Gradio: applicazioni web in python per AI [parte2]

Gradio è una libraria python che ci permette di creare applicazioni web in modo veloce e intuitivo per i nostri modelli di machine learning e AI. Le nostre applicazioni richiedono sempre un’interazione con l’utente e una personalizzazione del layout. Scopriamo, mediante degli esempi, come migliorare le nostre applicazioni.

Intelligenza artificiale

Gradio: applicazioni web in python per AI [parte1]

Scrivere applicazioni web per i nostri modelli di machine learning e/o di intelligenza artificiale può richiedere molto tempo e competenze che non sono in nostro possesso. Per snellire e velocizzare questo compito ci viene in aiuto Gradio, una libreria Python pensata per creare applicazioni web con poche righe di codice. Scopriamo le sue funzionalità base con alcuni esempi.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Design with MongoDB

Design with MongoDB!!!

Buy the new book that will help you to use MongoDB correctly for your applications. Available now on Amazon!