Skip to content

Storing Users with PookieDB

You already know how to store things in PookieDB. You stored patients - a Patient class with name and age. A user is exactly the same idea: just another model, just another table. The fields are different, but the pattern is identical.

If you want a reminder of how models work, see Defining Your First Table.


The User model

Create a database.py file with this:

import pookiedb
from flask_login import UserMixin

pookiedb.connect("sqlite:///users.sqlite3")

class User(UserMixin, pookiedb.Model):
    id       = pookiedb.UUIDField(auto=True, primary_key=True)
    username = pookiedb.CharField(max_length=100)
    password = pookiedb.CharField(max_length=200)

    class Meta:
        db_table = "users"

    def get_id(self):
        return str(self.id)

User.create_table()

UserMixin comes first in the class definition - that is how Python knows it is part of the class. pookiedb.Model comes second, same as always.

The id is a UUID - a long unique code that PookieDB generates automatically. You saw these in the CRUD group. If you want a refresher on why UUIDs, see PookieDB Refresher.


Why get_id()?

Flask-Login needs to get the user's ID as a plain string so it can store it and look the user up on the next request. get_id() is a short method that returns exactly that:

def get_id(self):
    return str(self.id)

self.id is a UUID object. str(self.id) turns it into a readable string like "f47ac10b-58cc-4372-a567-0e02b2c3d479". Flask-Login stores that string and hands it back to your user loader function later.


We never store the actual password

If you store passwords as plain text and someone ever reads your database - whether they hack it or just open the file - they have everyone's password instantly. That is a serious problem.

So we never store the real password. Instead we store a scrambled version of it.

Imagine taking your password and turning it into a jigsaw puzzle that has been completely mixed up. You cannot look at the scrambled pieces and figure out what the original picture was. But if someone gives you the original puzzle, you can check whether it matches the scrambled one.

That is exactly how password hashing works.


generate_password_hash and check_password_hash

These two functions come from a package called werkzeug - it is already installed because Flask uses it internally.

from werkzeug.security import generate_password_hash, check_password_hash

generate_password_hash takes a password and scrambles it:

generate_password_hash("mypassword")
# 'scrypt:32768:8:1$abc123...$a9f2b...'

Every time you run it, the result looks different - but both results still work. That is intentional and makes things more secure.

check_password_hash checks whether an entered password matches a stored scrambled one:

check_password_hash(stored_hash, "mypassword")   # True
check_password_hash(stored_hash, "wrongpassword") # False

It returns True or False. The original password is never revealed - not even to you.


Creating a test user - seed.py

We are not building a register page yet, so we need a way to create a user to test with. Write a small seed.py file and run it once:

from werkzeug.security import generate_password_hash
from database import User

User.objects.create(
    username="alice",
    password=generate_password_hash("password123")
)

print("User created.")

Run it:

python seed.py

Now the database has one user: username alice, password password123. You can log in with those on the next page.


Challenge

Create database.py and seed.py as shown. Run seed.py. No errors means the user was created successfully. Open the users.sqlite3 file in a database viewer if you have one - you should see one row in the users table with a scrambled password in the password column.


← Setting Up Flask-Login    Next: The Login Form →