Skip to content

Blog site demonstrating practical, fully featured app proficiency with Python Flask. Auth, CRUD, pagination, protected routes, error handling, recovery emails, etc.

jordanblakey/flask-in-depth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Flask In Depth

Set Up Virtual Environment (recommended)

pip install virtualenv
virtualenv venv
cd venv/bin
source venv/bin/activate(.fish|.zsh|.py) # will name (venv) if active
# `deactivate` # To leave

Installation

pip install -r requirements.txt # install all requirments
pip freeze > reqiurements.txt # save dependencies
python; import flask; exit() # if no error, installed correctly
pip list --local # List installed packages in current virtual environment
python run.py

Environment Variables

You'll need to supply a .env file with your projects keys:

# .env file at project root
SECRET_KEY=<32 byte hash>
DB_URI=<SQLite or PostgreSQL URI>
EMAIL_USER=<SMTP username of your choice. Using Mailjet.>
EMAIL_PASS=<SMTP password>
EMAIL_SENDER=<Email validated with SMTP service. Requires SPF and DKIM records.>

Project Structure

.
├── flaskblog
│   ├── config.py # App configuration
│   ├── forms.py # WTForm definitions
│   ├── __init__.py # Init app, init ORM, import routes
│   ├── models.py # SQLAlchemy models
│   ├── static/ # Static CSS, JS, images
│   ├── main/ # Main blueprint (__init__, routes, forms, utils)
│   ├── posts/ # Posts blueprint (__init__, routes, forms, utils)
│   ├── site.db # SQLite3 Database
│   ├── templates/ # Jinja2 templates
│   └── users/ # Users blueprint (__init__, routes, forms, utils)
├── requirements.txt # Manifest of dependencies
├── run.py # Flask entry point
├── .env # Environment variables
└── venv/ # virtualenv dir (optional)

Flask Snippets

# ALL ##########################################################
# BASE: hw | route | routegp | routep |
# APP: fapp | froute | furl | fmeth | frt | ftreq | fup | fsup | frc | fsc | feh | flog
# TEMPLATING: fexp | ffilter | fcomment | fblock | fextends | fself | fsuper | ffor | fif | fife | felif | fmacro | ffb | fset | finclude | fimport | fautoescape | furl

SQLAlchemy Commands

# import ORM instance from module
>>> from flaskblog import db
# Create tables as defined by ORM instance
>>> db.create_all()
>>> from flaskblog import User, Post
# Create ORM row instance
>>> user_1 = User(username='test', email='test@test.test', password='test')
# Create ORM row instance
>>> post_1 = Post(title='Blog 1', content='First Post Content!', user_id=user.id)
# Stage changes in memory
>>> db.session.add(user_1)
>>> db.session.add(post_1)
# Write changes to database
>>> db.session.commit()
# Discard uncommited changes from session (error handling)
>>> db.session.rollback()
# SELECT * FROM user
>>> User.query.all()
# SELECT * FROM user WHERE * username = 'test'
>>> User.query.filter_by(username='test').all()
# SELECT * FROM user LIMIT 1
>>> User.query.first()
# SELECT * FROM user WHERE * username = 'test' LIMIT 1
>>> user = User.query.filter_by(username='test').first()
# 1
>>> user.id
# Shows hashed password
>>> user.password
# query by id
>>> user = User.query.get(1)
# Collection of Post instances (db rows)
# Loop through rows and print all (note posts mapped with user.id:post.user_id)
>>> for post in user.posts:
# uses backref="author" from User class
# Note post table has no column 'author', while post.user_id is the foreign key used to get the 'author' row
...     print(post.author, post.user_id)
# Delete a row/rows stored from query
>>> db.session.delete(user)
>>> db.session.commit()
# flush the database
>>> db.drop_all()
# create tables again in empty state
>>> db.create_all()

Password Hashing With BCrypt

>>> from flask import Bcrypt
>>> bcrypt = Bcrypt()
# Generates a different hash every time, preventing hash table attacks
>>> hashed_pw = bcrypt.generate_password_hash('testing').decode('utf-8')
>>> bcrypt.check_password_hash(hashed_pw, 'password') # False
>>> bcrypt.check_password_hash(hashed_pw, 'testing') # True

SQLite3 Basics

Basic Operation & Config

sqlite3 #open the cli tool
.exit # exit the cli tool
.open <filename.db> #open local database
.show # print all SQLite config options
.mode column # Pretty print stdout as columns
.headers (on|off) # In col view, toggle column headers

Recon

.database #list the current database
.databases #list all databases (in the current directory?)
.schema #print out the db schema
.schema <tablename> # print the schema for a single table
.indexes # print all indexes in the current database
.indexes <tablename> # print all indexes in a single table
.tables #list all tables
.table <tablename> #check for the existence of table

Queries

.output post.txt
SELECT \* FROM post LIMIT 10; #output query results to file.
'SELECT \* FROM post LIMIT 10;' > commands.txt; sqlite3;
.open <filename.db>
.read commands.txt # Read SQL statements from a file.

Duplicating Data

CREATE TEMPORARY TABLE tmp AS SELECT * FROM post;
UPDATE tmp SET id = NULL;
INSERT INTO src SELECT * FROM post;
DROP TABLE tmp;

About

Blog site demonstrating practical, fully featured app proficiency with Python Flask. Auth, CRUD, pagination, protected routes, error handling, recovery emails, etc.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published