Flask uses the MVC (Model View Controller) Framework. Just to make this as obvious as possible, I like my Flask apps to have the following.
- Model -> models.py
- View -> views.py
- Controller -> __init__.py
Let's say your Flask app has the following structure.
├── main.py
├── database (directory)
│ ├── example.db
├── my-project (directory)
│ ├── __init__.py
│ ├── views.py
│ ├── models.py
│ ├── templates (directory)
│ │ ├── base.html
│ │ ├── home.html
│ │ ├── results.html
│ └── static (directory)
│ └── custom.css
Often, the logic for the initial setup of the database is placed in __init__.py. The create_all function will:
- Create the example.db file if it doesn't exist
- Create the tables in models.py if they don't exist
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def app_obj():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db.init_app(app)
with app.app_context():
db.create_all()
print("Created example.db SQLLite Database")
return app
This assumes you already have some sort of sign in form that is used to check if a users username and password are valid.
Let's say models.py contains the following. In this example, the name of the table will be "users". Notice there is a "password" column.
from . import db
from sqlalchemy import func, select
class users(db.Model):
id = db.Column(db.Integer, nullable=False, unique=True, primary_key=True)
date_created = db.Column(db.DateTime(timezone=True), default=func.now())
date_updated = db.Column(db.DateTime(timezone=True), onupdate=func.now())
email = db.Column(db.String(100), nullable=False, unique=True)
password = db.Column(db.String(200), nullable=False, unique=False)
werkzeug.security can be used to generate_password_hash. This should create a record in the table where the password is hashed, something like sha256$125QdsTMsBEGH2u2$2e0fca723217622070380e7d64a94eced75c9f9c38236d6d6f78e9e72860ceb0.
from flask import Blueprint, render_template
from sqlalchemy import func
from . import app, db
from .models import users
from werkzeug.security import generate_password_hash
views = Blueprint('views', __name__)
@views.route('/')
def home():
data = users(
username='john.doe',
password=generate_password_hash('itsasecret', method='sha256'),
date_updated=func.now()
)
db.session.add(data)
db.session.commit()
return render_template('home.html')
check_password_hash can be used to validate if the password is correct, assuming you know the plaintext password. This is often used when users sign in, since the user will be passing in their password. True will be returned if the hash password resolves to the users cleartext password. If not, False will be returned.
import re
from flask import Blueprint, render_template
from sqlalchemy import func
from . import app, db
from .models import users
from werkzeug.security import check_password_hash
@views.route('/SignIn')
def signin():
username = request.form.get('username').strip()
password = request.form.get('password').strip()
data = users.query.filter_by(username=username).first()
try:
password_hash = check_password_hash(data.password, password)
except TypeError:
print(f"TypeError perhaps means the password was created with an encryption protocol that is no longer supported such as sha256 instead of scrypt")
except ValueError:
print(f"ValueError perhaps means the password was created with an encryption protocol that is no longer supported such as sha256 instead of scrypt")
# these print statements are just used for debugging, to display the output on the console
print(f"data.username = {data.username}")
print(f"data.password = {data.password}")
print(f"password_hash = {password_hash}")
if password_hash == True:
print("password is valid")
else:
print("bad password")
return render_template('signin.html')
Did you find this article helpful?
If so, consider buying me a coffee over at