flask/docs/patterns/sqlite3.rst
Gennady Kovshenin 82b29c09ac Use sqlite3.Row factory in Flaskr
As pointed out in issue #588 sqlite3.Row should be used instead of
using casting to dict(). Also altered the "Easy Querying" Patterns
example to include the more correct way to return rows as dicts.
Did not touch Tutorial examples ("Views"), as these are not up to
date with the current Flaskr code, and the "Show Entries" section
points out the "Easy Querying" section on how to convert to a
dict().
2012-11-05 06:00:46 +06:00

134 lines
4.2 KiB
ReStructuredText

.. _sqlite3:
Using SQLite 3 with Flask
=========================
In Flask you can implement the opening of database connections on demand
and closing it when the context dies (usually at the end of the request)
easily.
Here is a simple example of how you can use SQLite 3 with Flask::
import sqlite3
from flask import _app_ctx_stack
DATABASE = '/path/to/database.db'
def get_db():
top = _app_ctx_stack.top
if not hasattr(top, 'sqlite_db'):
top.sqlite_db = sqlite3.connect(DATABASE)
return top.sqlite_db
@app.teardown_appcontext
def close_connection(exception):
top = _app_ctx_stack.top
if hasattr(top, 'sqlite_db'):
top.sqlite_db.close()
All the application needs to do in order to now use the database is having
an active application context (which is always true if there is an request
in flight) or to 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.
Example::
@app.route('/')
def index():
cur = get_db().cursor()
...
.. note::
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.
Connect on Demand
-----------------
The upside of this approach (connecting on first use) is that this will
only opening the connection if truly necessary. If you want to use this
code outside a request context you can use it in a Python shell by opening
the application context by hand::
with app.app_context():
# now you can use get_db()
.. _easy-querying:
Easy Querying
-------------
Now in each request handling function you can access `g.db` to get the
current open database connection. To simplify working with SQLite, a
row factory function is useful. It is executed for every result returned
from the database to convert the result. For instance in order to get
dictionaries instead of tuples this can be used::
def make_dicts(cursor, row):
return dict((cur.description[idx][0], value)
for idx, value in enumerate(row))
db.row_factory = make_dicts
Or even simpler::
db.row_factory = sqlite3.Row
Additionally it is a good idea to provide a query function that combines
getting the cursor, executing and fetching the results::
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
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 raw
cursor and connection objects.
Here is how you can use it::
for user in query_db('select * from users'):
print user['username'], 'has the id', user['user_id']
Or if you just want a single result::
user = query_db('select * from users where username = ?',
[the_username], one=True)
if user is None:
print 'No such user'
else:
print the_username, 'has the id', user['user_id']
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
the SQL statement with string formatting because this makes it possible
to attack the application using `SQL Injections
<http://en.wikipedia.org/wiki/SQL_injection>`_.
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
a function that creates the database based on that schema. This function
can do that for you::
def init_db():
with app.app_context():
db = get_db()
with app.open_resource('schema.sql') as f:
db.cursor().executescript(f.read())
db.commit()
You can then create such a database from the python shell:
>>> from yourapplication import init_db
>>> init_db()