I had started a web project on flask which required firebase at backend and by a little search over web found pyrebase — a python wrapper for Firebase. Everything about pyrebase is fine. But there’s one thing that is frustrating 😒😒😒. And the thing is it lacks any official documentation in a well explained manner. If you don’t have experience using Firebase on web using javascript especially. You will find the thing very much frustrating as was with me. At a point of time I even thought of quitting project to some other database platform. But then decided to explore offical Firebase documentation for web and Android and had come up with this blog on the understanding that I got from the blog.
So let’s start. First of all I hope you all have basic understanding of flask or any python web framework. If not better first refer any official documentation of any python framework then come back to have look at this blog.
First of all create a flask project with any name here I name it demo.
Next congigure the flask app the way you want I have configured it as follows
__init__.py
from flask import Flask
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
from application import routes
if __name__ == “__main__”:
app.run()
routes.py
.flaskenv
main.py
from application import app
Now once we are done with configuring and setting up the basic requirement for the app. We will be installing pyrebase to our project. So let’s do it:
pip install pyrebase4
- * pyrebase older version is having issues. So for flawless experience I would suggest better stick with pyrebase4.
Next we will configure our project in the firebase console.
Click on Add Project
Give the app some name and continue
Once you are done with the app configuration. The page similar to this pop up
Next select the web option(the one with the < sign). Next follow the instruction below:
- Next name your web app as instructed.
- Copy the content of “firebaseConfig” variable to be pasted inside __init__.py as shown below.
Next initialize firebase as shown above
and then initialize auth and database and if required the storage in the similar fashion.
Once done we will be importing db,auth to routes.py for further use. So let’s do as shown below
form application import db,auth
Now we will be dealing with the real portion for which this whole blog was supposed to be dedicated:
Inside routes.py we will first be dealing with login and signup
Signup with email and password:
user = auth.create_user_with_email_and_password(“youremail@gmail.com”,”1234567")
This will create an authentication account for your actions in the app
- *** Before heading forward and running your app. First go to the authentication inside your Firebase console and enable Email option inside sign In Method
The final code would look like this:
Next we will be performing action like sign in, accessing the token of the new user created, verifying the new user created, deactivating the account of the user created etc.
Sign In:
# To sign in user using email and password
sign_user = auth.sign_in_with_email_and_password(“Parasmani300@gmail.com”, “1234567”)
Sending Verification Mail
#Sending the account confirmation mail to the user email on successfull sign in
auth.send_email_verification(sign_user[‘idToken’])
Send Password Reset Email
# Sending Password reset email
reset_email = auth.send_password_reset_email(“youremail@gmail.com”)
Next We will explore what are the account info we can get as account info by signing in using firebase
Get Account Info using user token
token = session[‘user’]
- * generally token is passed to other pages of the web by creating session. Here in this case also as you can clearlly se from the code that I have passed the token from the session only
token = session[‘user’]
user = auth.get_account_info(token)
This will give us a whole bunch of information. A sample demo of information provided is
{‘kind’: ‘identitytoolkit#GetAccountInfoResponse’, ‘users’: [{‘localId’: ‘c110Hzo426NIc2F1psSqdCV92Go2’, ‘email’: ‘youremail@gmail.com’, ‘passwordHash’: ‘UkVEQUNURUQ=’, ‘emailVerified’: True, ‘passwordUpdatedAt’: 1596736732383, ‘providerUserInfo’: [{‘providerId’: ‘password’, ‘federatedId’: ‘youremail@gmail.com’, ‘email’: ‘youremail@gmail.com’, ‘rawId’: ‘youremail@gmail.com’}], ‘validSince’: ‘1596736732’, ‘lastLoginAt’: ‘1596737537530’, ‘createdAt’: ‘1596730349180’, ‘lastRefreshAt’: ‘2020–08–06T18:12:18.546Z’}]}
This is the whole bunch of information accessed by authenticating through email and password through firebase. I took almost all the over head of the user to mantain backend like password hashing, update/create date and time etc.
These information can be eaisly manipulated for use in python with a small knowledge of dictionary and list.
Beside these important firebase use cases, there is one method left to explore and that is :
verify_password_reset_code(reset_code,new_password)
Database:
All right we are almost done with firebase authentication. So the next task would be exploring firebase database and of course using pyrebase. So first of all make a to do list of the things which we will be going to read in this whole section or rather the list of methods that pyrebase supports as of now the blog is being written:
order_by_key ,order_by_value, order_by_child ,start_at, end_at, equal_to, limit_to_first, limit_to_last, shallow, child, get,push,set,update,remove,stream,check_token,generate_key,sort
So lets begin with basic one and with time we will be increasing the complexity. The best part of using these methods is, it can be chained in a certain sequence, such that result of one can be passed/filtered by the other
So lets start
- *Note: Here I am performing all database operation in test mode. I you want to perform action in production mode then don’t forget to add token as last parameter of every parameter. For instance to push a child to database:
db.child(“user”).push(“abc”,token)
Here ‘token’ is optional for public mode but become compulsory for private/production mode.
New path can be made in database using child() method
e.g: new_path = db.child(“new_path”)
or in case a more shallow path is required then we can easily create child of child as shown
db.child(“new_path”).child(“other_path”)
Saving data to database:
A point to be noted before inserting any data to the database in a firebase. A firebase databse is a NO SQL database. So it can directly save the data either as JSON/JSON Array or a direct String. So any data being inserted to kept in mind that it is being inserted either as json/string
Here the data can be saved in two ways:
- push (each data saved with auto generated, timestamped-based key)
- set( if custom key is required for each data being pushed then it can be used)
Push
To save data with a unique, auto-generated, timestamp-based key, use the push()
method.
u = db.child(“user”).push(json_data)
This will create a node in the sequence as shown:
database_name -> user -> system generated key -> json data
We will be visualizing the same through the code below also
SET
To create your own keys use the set()
method
There can be multiple cases where the user/organization may not want the key not to be randomly generated(timestamped), they rather want it to be of particular sequence as we can see in bank account and all
Here we will be moving with the example of the e-commerce cart. A randomly generated cart id really can be a headache to serve. Rather using the uid (token) generated during the user sign in/sign up could be a lot easier method to track and here with the help of set we will doing the same.
Lets demonstrate:
db.child(‘new_node’).child(localId).set(json_data)
… Refer in code for localId
With this we are done with the CREATE of CRUD. So next let’s move to READ/ RETRIEVE operation
READ
The most common way to demonstrate read operation is get() and here we will also will be using get as a starter.
- * As clear from the previous discussion on the implication of child that by chaining child we reach to some path where we are supposed to read/write/update/remove the data.
user = db.child(“user”).get()
This will return an object of type <pyrebase.pyrebase.PyreResponse object at 0x000001DF2702A340>. The element of the object can be obtained by iterating over the object as follows:
for u in user.each():
print(u.val()[‘name’])
With u.val() giving dictionary the element can be retrieved by its name as shown above.
No of element in the list:
len(db.child(“user”).get().val())
— — — — path.get().val() gives the list of the value at that node
shallow
To return just the keys at a particular path use the shallow()
method.
#to get only the keys of the user at particular path
all_user_ids = db.child(“user”).shallow().get()
print(all_user_ids.val())
streaming
You can listen to live changes to your data with the stream()
method.
def stream_handler(message):
print(message["event"]) # put
print(message["path"]) # /-K7yGTTEp7O549EzTYtI
print(message["data"]) # {'title': 'Pyrebase', "body": "etc..."}my_stream = db.child("posts").stream(stream_handler)
You can also add a stream_id
to help you identify a stream if you have multiple running:
my_stream = db.child("posts").stream(stream_handler, stream_id="new_posts")
close the stream
my_stream.close()
All right so we are done with the read operations basically So lets jump into update operation and then some complex chaining.
Update:
update
To update data for an existing entry use the update()
method.
db.child("users").child("Morty").update({"name": "Mortiest Morty"})
multi-location updates
You can also perform multi-location updates with the update()
method.
data = {
"users/Morty/": {
"name": "Mortimer 'Morty' Smith"
},
"users/Rick/": {
"name": "Rick Sanchez"
}
}db.update(data)
To perform multi-location writes to new locations we can use the generate_key()
method.
data = {
"users/"+ref.generate_key(): {
"name": "Mortimer 'Morty' Smith"
},
"users/"+ref.generate_key(): {
"name": "Rick Sanchez"
}
}db.update(data)
remove
To delete data for an existing entry use the remove()
method.
db.child("user").child(some_key).remove()
Lets demonstrate all with examples now. To clear the understanding and all
Now lets demonstrate some complex operation i.e chaining and all
Complex Queries
Queries can be built by chaining multiple query parameters together.
users_by_name = db.child("users").order_by_child("name").limit_to_first(3).get()
This query will return the first three users ordered by name.
order_by_child
We begin any complex query with order_by_child()
.
users_by_name = db.child("users").order_by_child("name").get()
This query will return users ordered by name.
equal_to
Return data with a specific value.
users_by_score = db.child("users").order_by_child("score").equal_to(10).get()
This query will return users with a score of 10.
start_at and end_at
Specify a range in your data.
users_by_score = db.child("users").order_by_child("score").start_at(3).end_at(10).get()
This query returns users ordered by score and with a score between 3 and 10.
limit_to_first and limit_to_last
Limits data returned.
users_by_score = db.child("users").order_by_child("score").limit_to_first(5).get()
This query returns the first five users ordered by score.
order_by_key
When using order_by_key()
to sort your data, data is returned in ascending order by key.
users_by_key = db.child("users").order_by_key().get()
order_by_value
When using order_by_value()
, children are ordered by their value.
users_by_value = db.child("users").order_by_value().get()
With this I think we are almost done. As a reference the github reference for pyrebase “thisbejim” has been used.
Special thanks to
You can follow me on github at:
Thank you all for reading and keep supporting.