2010-04-18 13:35:40 +02:00
Using SQLite 3 with Flask
=========================
2023-01-26 16:20:41 +00:00
A simple way of using SQLite 3 with Flask is to open a connection at the
start of each request and close it at the end. Since Flask processes requests
on separate threads, this means we don't have to think about the dynamics of
sharing a database connection across threads.
A more advanced approach may be to maintain a global pool of connections, as
that would avoid some overhead - but we consider that to be out of the scope
of this document.
2010-04-18 13:35:40 +02:00
2023-01-26 16:20:41 +00:00
Here is an example of how to create a connection and store it on the
thread-global `` g `` , then close it when the context is torn down::
2010-04-18 13:35:40 +02:00
import sqlite3
2013-06-09 12:30:27 +01:00
from flask import g
2010-04-18 13:35:40 +02:00
DATABASE = '/path/to/database.db'
2012-10-09 14:02:32 -05:00
def get_db():
2013-06-09 12:30:27 +01:00
db = getattr(g, '_database', None)
if db is None:
2014-02-08 22:14:23 +00:00
db = g._database = sqlite3.connect(DATABASE)
2013-06-09 12:30:27 +01:00
return db
2010-04-18 13:35:40 +02:00
2012-10-09 14:02:32 -05:00
@app.teardown_appcontext
def close_connection(exception):
2013-06-09 12:30:27 +01:00
db = getattr(g, '_database', None)
if db is not None:
db.close()
2010-04-18 13:35:40 +02:00
2014-11-03 12:04:25 -05:00
Now, to use the database, the application must either have an active
2023-01-26 16:20:41 +00:00
application context (which is always true if there is an ongoing request)
2014-11-03 12:04:25 -05:00
or create an application context itself. At that point the `` get_db ``
function can be used to get the current database connection. Whenever the
context is destroyed the database connection will be terminated.
2011-08-25 20:56:43 +01:00
2012-10-09 14:02:32 -05:00
Example::
2011-08-25 20:56:43 +01:00
2012-10-09 14:02:32 -05:00
@app.route('/')
def index():
cur = get_db().cursor()
...
2011-05-27 20:21:41 +02:00
2012-10-09 14:02:32 -05:00
.. note ::
2011-05-27 20:21:41 +02:00
2012-10-09 14:02:32 -05:00
Please keep in mind that the teardown request and appcontext functions
are always executed, even if a before-request handler failed or was
never executed. Because of this we have to make sure here that the
database is there before we close it.
2011-05-27 20:21:41 +02:00
2012-10-09 14:02:32 -05:00
Connect on Demand
-----------------
2011-05-27 20:21:41 +02:00
2012-10-09 14:02:32 -05:00
The upside of this approach (connecting on first use) is that this will
2014-09-27 18:39:43 -07:00
only open the connection if truly necessary. If you want to use this
2012-10-09 14:02:32 -05:00
code outside a request context you can use it in a Python shell by opening
the application context by hand::
2011-05-27 20:21:41 +02:00
2012-10-09 14:02:32 -05:00
with app.app_context():
# now you can use get_db()
2010-04-18 13:35:40 +02:00
Easy Querying
-------------
2017-12-08 15:18:02 -05:00
Now in each request handling function you can access `get_db()` to get the
2010-06-28 11:52:32 +08:00
current open database connection. To simplify working with SQLite, a
2012-10-09 14:02:32 -05:00
row factory function is useful. It is executed for every result returned
2014-09-27 18:39:43 -07:00
from the database to convert the result. For instance, in order to get
2017-02-11 01:43:11 -08:00
dictionaries instead of tuples, this could be inserted into the `` get_db ``
2016-06-14 23:55:47 -07:00
function we created above::
2012-10-09 14:02:32 -05:00
def make_dicts(cursor, row):
2013-07-31 22:06:15 -04:00
return dict((cursor.description[idx][0], value)
2012-10-09 14:02:32 -05:00
for idx, value in enumerate(row))
db.row_factory = make_dicts
2010-04-18 13:35:40 +02:00
2016-06-14 23:55:47 -07:00
This will make the sqlite3 module return dicts for this database connection, which are much nicer to deal with. Even more simply, we could place this in `` get_db `` instead::
2012-11-05 06:00:46 +06:00
db.row_factory = sqlite3.Row
2016-06-14 23:55:47 -07:00
This would use Row objects rather than dicts to return the results of queries. These are `` namedtuple `` s, so we can access them either by index or by key. For example, assuming we have a `` sqlite3.Row `` called `` r `` for the rows `` id `` , `` FirstName `` , `` LastName `` , and `` MiddleInitial `` ::
>>> # You can get values based on the row's name
>>> r['FirstName']
John
>>> # Or, you can get them based on index
>>> r[1]
John
# Row objects are also iterable:
>>> for value in r:
... print(value)
1
John
Doe
M
2014-11-08 22:21:27 +01:00
Additionally, it is a good idea to provide a query function that combines
2012-10-09 14:02:32 -05:00
getting the cursor, executing and fetching the results::
2017-02-11 01:43:11 -08:00
2010-04-18 13:35:40 +02:00
def query_db(query, args=(), one=False):
2012-10-09 14:02:32 -05:00
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
2010-04-18 13:35:40 +02:00
return (rv[0] if rv else None) if one else rv
2017-02-11 01:43:11 -08:00
This handy little function, in combination with a row factory, makes
working with the database much more pleasant than it is by just using the
2014-09-27 18:39:43 -07:00
raw cursor and connection objects.
2010-04-18 13:35:40 +02:00
Here is how you can use it::
for user in query_db('select * from users'):
2021-10-16 02:04:07 +09:00
print(user['username'], 'has the id', user['user_id'])
2010-04-18 13:35:40 +02:00
Or if you just want a single result::
user = query_db('select * from users where username = ?',
[the_username], one=True)
if user is None:
2021-10-16 02:04:07 +09:00
print('No such user')
2010-04-18 13:35:40 +02:00
else:
2021-10-16 02:04:07 +09:00
print(the_username, 'has the id', user['user_id'])
2010-04-18 13:35:40 +02:00
To pass variable parts to the SQL statement, use a question mark in the
statement and pass in the arguments as a list. Never directly add them to
2010-10-06 14:05:35 +08:00
the SQL statement with string formatting because this makes it possible
2010-04-18 13:35:40 +02:00
to attack the application using `SQL Injections
2017-02-11 01:43:11 -08:00
<https://en.wikipedia.org/wiki/SQL_injection> `_.
2010-04-18 13:35:40 +02:00
Initial Schemas
---------------
Relational databases need schemas, so applications often ship a
`schema.sql` file that creates the database. It's a good idea to provide
2010-04-19 23:25:51 -05:00
a function that creates the database based on that schema. This function
2010-04-18 13:35:40 +02:00
can do that for you::
def init_db():
2012-10-09 14:02:32 -05:00
with app.app_context():
db = get_db()
2013-05-25 19:13:48 +02:00
with app.open_resource('schema.sql', mode='r') as f:
2010-04-18 13:35:40 +02:00
db.cursor().executescript(f.read())
db.commit()
2014-11-08 22:21:27 +01:00
You can then create such a database from the Python shell:
2010-04-18 13:35:40 +02:00
>>> from yourapplication import init_db
>>> init_db()