FlaskでのSQLite 3の使用 Using SQLite 3 with Flask

Flaskでは、必要に応じてデータベース接続を開き、コンテキストが無効になったとき(普通はリクエストの最後)閉じるように、容易に実装できます。 In Flask you can easily implement the opening of database connections on demand and closing them when the context dies (usually at the end of the request).

以下はFlaskでSQLite 3をどのように使用可能であるかのシンプルな例です: Here is a simple example of how you can use SQLite 3 with Flask::

import sqlite3
from flask import g

DATABASE = '/path/to/database.db'

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

このとき、データベースを使うために、アプリケーションは有効なアプリケーションのコンテキストを持つ(処理中のリクエストがある場合はこれは常にtrueです)か、アプリケーションのコンテキスト自信を作成する必要があります。この時点でget_db関数はその時のデータベース接続を取得するために使用できます。コンテキストが破壊されるときは常に、データベース接続は終了されます。 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.

もしFlask 0.9またはより古いものを使用している場合、flask.gオブジェクトはアプリケーションのコンテキストではなくリクエストに結びついていた(was bound to)ため、gの代わりにflask._app_ctx_stack.topを使用する必要があります。 Note: if you use Flask 0.9 or older you need to use ``flask._app_ctx_stack.top`` instead of ``g`` as the :data:`flask.g` object was bound to the request and not application context.

Example::

@app.route('/')
def index():
    cur = get_db().cursor()
    ...

注釈

リクエスト前の処理器(handler)が失敗もしくは実行されない場合でさえも、リクエストおよびアプリケーションのコンテキストを取り壊す(teardown)関数は常に実行されます。このために、データベース(接続)を閉じる前に、データベース(接続)があるかを確認する必要があります。 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) Connect on Demand

このアプローチの利点(初めて使用するときに接続)は、本当に必要な場合だけ接続を開くことです。以下のコードをリクエストのコンテキストの外側で使用したい場合、手動でアプリケーションのコンテキストを開くことで、Pythonシェルの中で使用できます。 The upside of this approach (connecting on first use) is that this will only open 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

この時点で各リクエスト処理関数の中で、そのときの開かれたデータベース接続を取得するためにget_db()にアクセスできます。SQLiteを使った作業をシンプルにするために、rowファクトリー関数が便利です。それはデータベースから返されるすべての結果に対して、それを変換する実行されます。例えば、tupleの代わりにdictionaryを取得するために(訳注: tupleもdictionaryもPythonの組み込み型)、以下を先に作成したget_db関数に挿入することができます: Now in each request handling function you can access `get_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 could be inserted into the ``get_db`` function we created above::

def make_dicts(cursor, row):
    return dict((cursor.description[idx][0], value)
                for idx, value in enumerate(row))

db.row_factory = make_dicts

これは、より処理しやすいように、sqlite3モジュールがこのデータベース接続に対してはdictを返すようにします。より単純に、代わりに以下をget_dbの中に置けます: 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::

db.row_factory = sqlite3.Row

これは問合せ(query)の結果としてdictよりもRowオブジェクトを使用します。これらはnamedtupleであるため、インデックスまたはキーのどちらでもアクセスできます。例えば、idFirstNameLastNameMiddleInitialがある行に対する、rと呼ばれるsqlite3.Row(オブジェクト)があると仮定します: 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

さらに、カーソルの取得、(問合せを)実行、結果の取得をまとめた問合せ関数を提供するのはよい考えです: 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

この便利な小さい関数は、rowファクトリーと合わせて、データベースを使った作業を、直接カーソルおよび接続オブジェクトを使うときと比べてさらにより楽しいものにします。 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']

変数部分をSQL文へ渡すために、クエスチョンマークを文中に使用し、引数をlistとして渡します。文字列のformat機能ではSQLインジェクションを使ったアプリケーションへの攻撃が可能になるため、決して文字列のformat機能で変数部分をSQL文に直接加えないでください。 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 <https://en.wikipedia.org/wiki/SQL_injection>`_.

初期スキーマ(Initial Schemas) Initial Schemas

リレーショナルデータベースはスキーマを必要とするため、アプリケーションはしばしばデータベースを作成するschema.sqlファイルを出荷します。そのスキーマに基づいてデータベースを作成する関数を提供するのは良い考えです。それは以下の関数で実行できます: 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', mode='r') as f:
            db.cursor().executescript(f.read())
        db.commit()

それから、そのようなデータベースをPythonシェルから作成できます: You can then create such a database from the Python shell:

>>> from yourapplication import init_db
>>> init_db()