2010-04-18 19:35:40 +08:00
Using SQLite 3 with Flask
=========================
2025-09-13 05:52:03 +08:00
You can implement a few functions to work with a SQLite connection during a
request context. The connection is created the first time it's accessed,
reused on subsequent access, until it is closed when the request context ends.
2010-04-18 19:35:40 +08:00
2012-10-10 03:02:32 +08:00
Here is a simple example of how you can use SQLite 3 with Flask::
2010-04-18 19:35:40 +08:00
import sqlite3
2013-06-09 19:30:27 +08:00
from flask import g
2010-04-18 19:35:40 +08:00
DATABASE = '/path/to/database.db'
2012-10-10 03:02:32 +08:00
def get_db():
2013-06-09 19:30:27 +08:00
db = getattr(g, '_database', None)
if db is None:
2014-02-09 06:14:23 +08:00
db = g._database = sqlite3.connect(DATABASE)
2013-06-09 19:30:27 +08:00
return db
2010-04-18 19:35:40 +08:00
2012-10-10 03:02:32 +08:00
@app.teardown_appcontext
def close_connection(exception):
2013-06-09 19:30:27 +08:00
db = getattr(g, '_database', None)
if db is not None:
db.close()
2010-04-18 19:35:40 +08:00
2014-11-04 01:04:25 +08:00
Now, to use the database, the application must either have an active
application context (which is always true if there is a request in flight)
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-26 03:56:43 +08:00
2012-10-10 03:02:32 +08:00
Example::
2011-08-26 03:56:43 +08:00
2012-10-10 03:02:32 +08:00
@app.route('/')
def index():
cur = get_db().cursor()
...
2011-05-28 02:21:41 +08:00
2012-10-10 03:02:32 +08:00
.. note ::
2011-05-28 02:21:41 +08:00
2012-10-10 03:02:32 +08: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-28 02:21:41 +08:00
2012-10-10 03:02:32 +08:00
Connect on Demand
-----------------
2011-05-28 02:21:41 +08:00
2012-10-10 03:02:32 +08:00
The upside of this approach (connecting on first use) is that this will
2014-09-28 09:39:43 +08:00
only open the connection if truly necessary. If you want to use this
2012-10-10 03:02:32 +08:00
code outside a request context you can use it in a Python shell by opening
the application context by hand::
2011-05-28 02:21:41 +08:00
2012-10-10 03:02:32 +08:00
with app.app_context():
# now you can use get_db()
2010-04-18 19:35:40 +08:00
Easy Querying
-------------
2017-12-09 04:18:02 +08: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-10 03:02:32 +08:00
row factory function is useful. It is executed for every result returned
2014-09-28 09:39:43 +08:00
from the database to convert the result. For instance, in order to get
2017-02-11 17:43:11 +08:00
dictionaries instead of tuples, this could be inserted into the `` get_db ``
2016-06-15 14:55:47 +08:00
function we created above::
2012-10-10 03:02:32 +08:00
def make_dicts(cursor, row):
2013-08-01 10:06:15 +08:00
return dict((cursor.description[idx][0], value)
2012-10-10 03:02:32 +08:00
for idx, value in enumerate(row))
db.row_factory = make_dicts
2010-04-18 19:35:40 +08:00
2016-06-15 14:55:47 +08: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 08:00:46 +08:00
db.row_factory = sqlite3.Row
2016-06-15 14:55:47 +08: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-09 05:21:27 +08:00
Additionally, it is a good idea to provide a query function that combines
2012-10-10 03:02:32 +08:00
getting the cursor, executing and fetching the results::
2017-02-11 17:43:11 +08:00
2010-04-18 19:35:40 +08:00
def query_db(query, args=(), one=False):
2012-10-10 03:02:32 +08:00
cur = get_db().execute(query, args)
rv = cur.fetchall()
cur.close()
2010-04-18 19:35:40 +08:00
return (rv[0] if rv else None) if one else rv
2017-02-11 17: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-28 09:39:43 +08:00
raw cursor and connection objects.
2010-04-18 19:35:40 +08:00
Here is how you can use it::
for user in query_db('select * from users'):
2021-10-16 01:04:07 +08:00
print(user['username'], 'has the id', user['user_id'])
2010-04-18 19:35:40 +08: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 01:04:07 +08:00
print('No such user')
2010-04-18 19:35:40 +08:00
else:
2021-10-16 01:04:07 +08:00
print(the_username, 'has the id', user['user_id'])
2010-04-18 19:35:40 +08: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 19:35:40 +08:00
to attack the application using `SQL Injections
2017-02-11 17:43:11 +08:00
<https://en.wikipedia.org/wiki/SQL_injection> `_.
2010-04-18 19:35:40 +08: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-20 12:25:51 +08:00
a function that creates the database based on that schema. This function
2010-04-18 19:35:40 +08:00
can do that for you::
def init_db():
2012-10-10 03:02:32 +08:00
with app.app_context():
db = get_db()
2013-05-26 01:13:48 +08:00
with app.open_resource('schema.sql', mode='r') as f:
2010-04-18 19:35:40 +08:00
db.cursor().executescript(f.read())
db.commit()
2014-11-09 05:21:27 +08:00
You can then create such a database from the Python shell:
2010-04-18 19:35:40 +08:00
>>> from yourapplication import init_db
>>> init_db()