In today’s lab, you will be writing SQL queries inside Flask to communicate with an external SQLite database. This type of SQL is called embedded SQL
For more reference for writing embedded SQL in Flask, consult the Flask documentation. In tutorial, we will be going over the “vanilla” way of using SQLite with Flask using only the sqlite3
standard Python library. In lecture, Abbas uses the 3rd party library SQLAlchemy
but for your assignment, either strategy will be fine
The basic setup for a Flask app is similar to what we did in Week 6 with a couple extra functions to communicate with the database. The starter code for today’s lab has everything pre-written but we will go over the process if you are starting from scratch. This tutorial assumes you have the starter app.py
code from Week 6 lab
Setting up the database:
Note the required imports (there are more imports than in Week 6’s lab)
import sqlite3
from flask import Flask, render_template, request, g
# the database file we are going to communicate with
DATABASE = './database.db'
# connects to the database
def get_db():
# if there is a database, use it
db = getattr(g, '_database', None)
if db is None:
# otherwise, create a database to use
db = g._database = sqlite3.connect(DATABASE)
return db
# converts the tuples from get_db() into dictionaries
# (don't worry if you don't understand this code)
def make_dicts(cursor, row):
return dict((cursor.description[idx][0], value)
for idx, value in enumerate(row))
# given a query, executes and returns the result
# (don't worry if you don't understand this code)
def query_db(query, args=(), one=False):
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
return (rv[0] if rv else None) if one else rv
Whenever we want to query information from the database, we need to setup a connection with the database which is done using the function get_db()
. This function returns a database object of which we can apply queries to
There are two helper functions make_dicts()
and query_db()
. You do not need to know exactly how to write these two functions but they are very useful for querying data:
make_dicts()
query_db()
make_dicts()
, this return will be in the form of a dictionaryquery_db()
uses a database construct called a cursor to select the data based upon the query and then packages the result to finally return. Cursors are outside of the scope of this course so if this is confusing you don’t need to know this in great detailDatabase teardown:
Whenever you close the Flask application, you need to close any open connections you have to the database. Otherwise, the next time you access the database, you may be blocked by a connection that was still left open. To do this, we create a function that will be called on application teardown that will destroy any currently open connections
# this function must come after the instantiation of the variable app
# (i.e. this comes after the line app = Flask(__name__))
@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
# close the database if we are connected to it
db.close()
Querying data:
Querying data follows the same general structure:
get_db()
make_dicts
to convert the tuples to dictionariesGenerally, you want to do this wherever you use an @app.route
as your routing functions will generally have some sort of functionality tied to them. As an example, this is what it would look like if you were to do something in the default route (i.e. @app.route('/')
)
@app.route('/')
def root():
# get the database instance
db = get_db()
# convert tuples to dictionaries
db.row_factory = make_dicts
# query for the items
# (in this case, we do not have any request parameters)
items = []
for item in query_db('select * from items'):
items.append(item)
db.close()
return render_template('index.html', items=items)
Querying with request parameters:
@app.route('/')
def root():
# get the database instance
db = get_db()
# convert tuples to dictionaries
db.row_factory = make_dicts
# get request parameter
# (in this case, the request parameter is called "name")
name = request.args.get('name')
# query for the item by name
# because we are expecting this to return a single value, we set one=True
# (read query_db() for more details)
item = query_db('select * from items where name = ?', [name], one=True)
items.append(item)
db.close()
return render_template('index.html', items=items)
Two important notes about the above code:
query_db('select * from items where name = {name}'.format(name=name))
.format()
method to replace parameters leaves the code vulnerable to SQL injection
NOTE: you must do this exercise on your own computer; you will not be able to finish this lab on the lab computers
Today we are making an employee database application for the company Dunder Mifflin from the completely real documentary The Office. The application behaves as follows:
Starter code is given here
/
):
SELECT * FROM ...
query/employee
):
firstname
in the databaseSELECT * FROM employees WHERE firstname = ...
queryIf you need help during the lab please ask. If you would like to investigate the schema use the SQLite browser from earlier in the semester