Hey guys,
In one of my previous videos, we took an existing streamlit page and added a login form. So, only when the user provides the correct
credentials, they can access the web app. We did this with the help of the streamlit
authenticator package. In particular, we converted plain text passwords
into hashed ones. We then took the hashed passwords and stored
them in a pickle file. In the actual streamlit app, we loaded the
pickle file and used it for user authentication. I received many comments that storing the
credentials in an actual database would be even better. And this is exactly what we are going to do
in this video. We will start from where we left off in the
old video. So, if you have not seen it yet, I recommend
watching that video first. I will leave the link to the video in the
info card above. OK, and with that said, let us get started. As the first step, let us set up the database. I have decided to use the service from deta
cloud. Mainly because it is super easy to set up,
it is free, and I also use it for some of my hobby projects. To get started, navigate to "deta.sh." On this page, click on the 'Join Deta' button. The sign-up procedure is very straightforward. Just enter your username, password and email. Once done, you will get a confirmation email
with your activation link. After your account has been activated, you
can sign in. You might get this welcome message if you
log in for the first time. For now, you can close it. We will come back to our Project key in just
a moment. Deta offers three services. A cloud environment, a database and file storage. For this tutorial, we are only interested
in the database. Therefore, navigate to base and click on Python. Here you will find the steps to get started. As the first step, we are going to install
the deta SDK. To do so, open up your terminal or command
prompt, type pip install deta and hit enter. I already installed it. As the next step, let us get our project key. You can create a new key under your settings
by clicking 'Create Key'. As mentioned here, the key will only be shown
once, and you should store it in a safe place. Additionally, you do not want to expose the
key because anybody with this key would have access to your database. With that in mind, let me copy the key to
my clipboard. For the next step, I will create a new Python
file. I will call this Python script: database.py
In the file, I will import Deta from deta. After that, I will store our key in a variable. Later in the video, we will save the key in
an environment variable, but for now, we will keep things simple here. With our key, we can initialize a Deta object. With that object, we can now create or connect
to a database. All we need to do is to provide a name for
the database. I will call mine "users_db". OK, and with that in place, we are ready to
use our database. There is no need to predefine any table columns
with the respective type. Deta will do it automatically for us. I will define a function to insert a new entry
into our database. This function should take the username, name
and password as parameters. And it could not be easier. All you need to do is to use "put" on the
database object variable followed by the values you want to insert. You want to provide the values in a dictionary. There is only one thing I want to highlight. For the primary key, I am using the username. So, the username will be the unique identifier. There should not be multiple users with the
same username. With our function in place, let me test it
out. Like in the first video, I will create a user
for Peter Parker. The username will be pparker, and the password
is abc123. OK, if I now run this script and do not get
any errors, I successfully inserted the user. We could also validate this in our deta dashboard. After refreshing the page, you should see
the user's database on the left side. One of the features I really like about deta
is that it already comes with a simple graphical interface to manipulate the database. If you wanted to, you could also insert entries
directly from this interface. So, let me add another user to our database
and delete Peter Parker. Back in the script, let us now fetch all users
from our database. Also, this is super easy. You just need to type DB.fetch(). This will return an instance of a FetchResponse
class. This class has different properties. In our case, I want to return the items. And that is all there is to it. So, let me test it out by printing out all
users. It is a little bit hard to read, but here
in my text editor, I can see that we have only Rebecca Miller in our database. And those two functions are all we need for
our user authentication. However, just as a bonus, let me also show
some other useful queries, like getting back all the details from a particular user. If I run this query with our user rmiller,
we will get all fields in a python dictionary. Another useful function would be to update
any user. For this, we will need two things: the user
we want to update and the fields we want to change. You can specify the fields in a python dictionary. So, as an example, for the username rmiller,
I want to change the name to Rebecca Parker. After executing the script, we can validate
this update in our Dashboard. After a quick refresh, we can now see the
updated name. And last but not least, you might want to
delete a user. This is also very easy. You just need to type DB.delete followed by
the username. And as before, let me also test it out by
deleting rmiller. After running this script, we should see that
our database is empty again. OK, now that everything is working, let us
take care of our project key. As mentioned, we do not want to keep it hard
coded in our Python file. A better idea is to save it as an environment
variable. To do so, I will use a helper library, which
you can install via pip. This packge is called โpyhton dotenvโ. I already have it installed on my machine. So, back in my script, I will import os, a
core python module, and I will import load_dotenv from dotenv. Now I can load the environment variable by
using load_dotenv followed the filename. So, let us now create this .env file in the
same directory. Therefore, I will copy our key, create a new
text file and name it ".env". In this file, I will define a name as "Deta
Key" with our actual key. OK, after saving the file, I can switch back
to the Python script. Instead of our hard-coded key, I can now use
"os.getenv", and the name was deta key. Now that we have our .env file, you want to
avoid uploading it to GitHub or any other platform. Therefore, also ensure to create a gitignore
file. I usually use the service from gitignore.io. Just head over to their website, type python
and click on create. Then copy the whole text, go back to your
project folder, create a new text file and name it ".gitignore". In this text file, paste the text you just
copied. If you scroll up a bit, you will see that
git will ignore any kind of environment files. You might also want to add any other files
that you do not want to upload to your online Git repository. For example, I will add a small helper file
called "upload_to_database.py". We will use this file to insert some values
into our database. So, let me create quickly create this Python
script. In this file, we will need the streamlit authenticator
package and our local database file. Then I will define the usernames, names and
passwords. As in the previous video, I will convert the
plain text password to hashed ones. With those lists defined, I will insert each
user into our database. To do that, I will loop over all three lists
simultaneously using the zip function. I will insert a record with the username,
name, and hashed password within each iteration. To check if it is working and head over to
my deta dashboard. After a quick refresh, we will see our entires. OK, as this is all working now, I can delete
the files from the previous video, so the "generate.py" and the "pickle" file. Instead, we will get the users directly from
the database. So, here in my streamlit app, I can remove
the pathlib and pickle import as we will only need our local database.py file. In particular, we now want to retrieve the
names, usernames and passwords. So, let me delete the following lines and
fetch all the users from our database. We will return the users in a dictionary,
which will look like this. To pass it to our Authentication object, I
will convert the values to a list using a list comprehension. So for each user in users, I will store the
different keys in a separate list. And that is all there is to it. The rest of the code remains the same. Now, I can test it out by switching back to
my app. After a quick refresh, I will try to log in
with the username pparker. OK, this seems to be working. Yet, if I go back to my deta database and
delete peter parker from my table, we should get an error message in streamlit. So, let me try to log in again. As expected, we will get the following message. Likewise, we could also change any values
in our database, like changing the name to Rebecca parker. The username and password will remain the
same, but you can see the updated name in the Dashboard once logged in. Now you might be asking yourself how to deploy
this web application to the internet without exposing our database key to the public. And this depends on the hosting service you
are choosing. For example, if you are using Heroku, you
can configure the environment variables via the command-line interface tool or the Heroku
dashboard. So, you might want to check with your hosting
service how to upload those secret keys. OK, guys, and that is all for this tutorial. Thanks for watching, and see you in the next
video!