データベースの定義とアクセス Define and Access the Database

このアプリケーションではユーザ情報と投稿記事を格納するためにSQLiteデータベースを使用していきます。Pythonでは、組み込みのSQLiteサポートのsqlite3モジュールが一緒に提供されています。 The application will use a `SQLite`_ database to store users and posts. Python comes with built-in support for SQLite in the :mod:`sqlite3` module.

SQLiteは、データベースサーバを別に用意する必要がなく、Pythonに組み込まれているために便利です。しかし、もし並列なリクエストが同時にデータベースへの書き込みを試みた場合、それぞれの書き込みが直列で処理されるため、それらの処理は遅くなります。これは、小さなアプリケーションでは気付かないでしょう。もし大きくなってきたら、違うデータベースへ切り替えたくなるかもしれません。 SQLite is convenient because it doesn't require setting up a separate database server and is built-in to Python. However, if concurrent requests try to write to the database at the same time, they will slow down as each write happens sequentially. Small applications won't notice this. Once you become big, you may want to switch to a different database.

このチュートリアルではSQLについての詳細には深入りしません。もしSQLに慣れていない場合は、SQLiteのドキュメントがSQL言語を説明しています。 The tutorial doesn't go into detail about SQL. If you are not familiar with it, the SQLite docs describe the `language`_.

データベースへの接続 Connect to the Database

SQLiteデータベース(および殆どのPythonの他のデータベースライブラリ)を使って作業するとき最初にすることは、データベースへの接続(connection)の作成です。どのような問合せ(queries)や操作(operations)も、connectionを使用しながら実施され、作業が終了した後はconnectionが閉じられ(close)ます。 The first thing to do when working with a SQLite database (and most other Python database libraries) is to create a connection to it. Any queries and operations are performed using the connection, which is closed after the work is finished.

webアプリケーションでは、このconnectionは典型的にはリクエストと結び付けられます。それはリクエスト処理中のどこかの時点で作成され、レスポンスが送信される前に閉じられます。 In web applications this connection is typically tied to the request. It is created at some point when handling a request, and closed before the response is sent.

flaskr/db.py
import sqlite3

import click
from flask import current_app, g
from flask.cli import with_appcontext


def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect(
            current_app.config['DATABASE'],
            detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Row

    return g.db


def close_db(e=None):
    db = g.pop('db', None)

    if db is not None:
        db.close()

gは特別なオブジェクトで、リクエストごとに個別なものになります。それは、リクエストの(処理)期間中は複数の関数によってアクセスされるようなデータを格納するために使われます。connectionは(gオブジェクトに)格納されて、もしも同じリクエストの中でget_dbが2回呼び出された場合、新しいconnectionを作成する代わりに、再利用されます。 :data:`g` is a special object that is unique for each request. It is used to store data that might be accessed by multiple functions during the request. The connection is stored and reused instead of creating a new connection if ``get_db`` is called a second time in the same request.

current_appはもうひとつの特別なオブジェクトで、リクエストを処理中のFlaskアプリケーションを指し示します。application factoryを利用しているため、残りのコードを書いているときは、アプリケーションのオブジェクトは存在しません(訳注: Flaskアプリを作成するコードはapplication factoryだけで、その他の箇所ではapplication factoryを呼んでアプリケーションのインスタンスを直接作成・利用するコードは基本的に書かないというような意味合いだと思います)。get_dbが呼び出されるのは、アプリケーションが作成されてリクエストを処理しているときであるため、current_appが使用できます。 :data:`current_app` is another special object that points to the Flask application handling the request. Since you used an application factory, there is no application object when writing the rest of your code. ``get_db`` will be called when the application has been created and is handling a request, so :data:`current_app` can be used.

sqlite3.connect()は、設定の(訳注: current_app.configの)キーDATABASEで示されるファイルへのconnectionを確立します。このファイルはまだ存在せず、後程データベースを初期化するまで存在しないままです。 :func:`sqlite3.connect` establishes a connection to the file pointed at by the ``DATABASE`` configuration key. This file doesn't have to exist yet, and won't until you initialize the database later.

sqlite3.Rowは、dictのように振る舞う行を返すようにconnectionへ伝えます。これは列名による列へのアクセスを可能にします。 :class:`sqlite3.Row` tells the connection to return rows that behave like dicts. This allows accessing the columns by name.

close_dbは、g.dbが設定されているか調べることでconnectionが作成済みであるかを調べます。もしconnectionが存在した場合は、それを閉じます。(この文書の)後の方では、各リクエストの後で呼び出されるように、application factoryの中でclose_db関数についてアプリケーションに伝えます。 ``close_db`` checks if a connection was created by checking if ``g.db`` was set. If the connection exists, it is closed. Further down you will tell your application about the ``close_db`` function in the application factory so that it is called after each request.

表(table)の作成 Create the Tables

SQLiteでは、データは表(tables)列(columns)に格納されます。これらはデータを格納および取得できるようになる前に作成されている必要があります。Flaskrではユーザ情報はuser表に、投稿記事はpost表に格納していきます。空の表を作成するために必要なSQLコマンドのファイルを作成します: In SQLite, data is stored in *tables* and *columns*. These need to be created before you can store and retrieve data. Flaskr will store users in the ``user`` table, and posts in the ``post`` table. Create a file with the SQL commands needed to create empty tables:

flaskr/schema.sql
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;

CREATE TABLE user (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  username TEXT UNIQUE NOT NULL,
  password TEXT NOT NULL
);

CREATE TABLE post (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  author_id INTEGER NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  FOREIGN KEY (author_id) REFERENCES user (id)
);

これらのSQLコマンドを実行するPython関数をdb.pyファイルに追加します: Add the Python functions that will run these SQL commands to the ``db.py`` file:

flaskr/db.py
def init_db():
    db = get_db()

    with current_app.open_resource('schema.sql') as f:
        db.executescript(f.read().decode('utf8'))


@click.command('init-db')
@with_appcontext
def init_db_command():
    """Clear the existing data and create new tables."""
    init_db()
    click.echo('Initialized the database.')

open_resource()は、パッケージflaskrから相対的な場所で指定されたファイルを開きます。後でアプリケーションをデプロイしたとき、アプリケーションの場所を知らなくてもファイルが開けるため、それは便利です。get_dbは、ファイルから読み取ったコマンドを実行するために使用される、データベースのconnectionを返します。 :meth:`open_resource() <Flask.open_resource>` opens a file relative to the ``flaskr`` package, which is useful since you won't necessarily know where that location is when deploying the application later. ``get_db`` returns a database connection, which is used to execute the commands read from the file.

click.command()は、init_db関数を呼び出して成功時のメッセージを表示する、init-dbと呼ばれる、コマンドラインから使用できるコマンドを定義します。Callを読むと、command作成に関してさらに学習できます。 :func:`click.command` defines a command line command called ``init-db`` that calls the ``init_db`` function and shows a success message to the user. You can read :ref:`cli` to learn more about writing commands.

アプリケーションへの登録 Register with the Application

このclose_dbinit_db_command関数はアプリケーションのインスタンスに登録される必要があります; さもなければ、アプリケーションによって使用されないでしょう。しかしながら、このアプリケーションではfactory関数を使用しているので、(close_dbとinit_db_command)関数を書いているときはアプリケーションのインスタンスが利用可能ではありません(訳注: factoryを使わずモジュールの変数にapp = Flask(__name__)とインスタンスを格納したときのように、関数からアプリケーションのインスタンスに直接アクセスできないというような意味合い)。代わりに、アプリケーションを受け取って登録を行う関数を作成します。 The ``close_db`` and ``init_db_command`` functions need to be registered with the application instance; otherwise, they won't be used by the application. However, since you're using a factory function, that instance isn't available when writing the functions. Instead, write a function that takes an application and does the registration.

flaskr/db.py
def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)

app.teardown_appcontext()は、レスポンスを返した後のクリーンアップを行っているときに、上記の関数(close_db)を呼び出すように、Flaskへ伝えます。 :meth:`app.teardown_appcontext() <Flask.teardown_appcontext>` tells Flask to call that function when cleaning up after returning the response.

app.cli.add_command()は、flaskコマンドを使って呼び出すことができる新しいコマンドを追加します。 :meth:`app.cli.add_command() <click.Group.add_command>` adds a new command that can be called with the ``flask`` command.

factoryからこの関数をimportして呼び出します。新しいコードをfactory関数の最後でappを返す前に置きます。 Import and call this function from the factory. Place the new code at the end of the factory function before returning the app.

flaskr/__init__.py
def create_app():
    app = ...
    # existing code omitted

    from . import db
    db.init_app(app)

    return app

データベースファイルの初期化 Initialize the Database File

この時点でinit-dbはappに登録され、前のページでのrunコマンドと似たように、flaskコマンドを使用して呼び出すことができます。 Now that ``init-db`` has been registered with the app, it can be called using the ``flask`` command, similar to the ``run`` command from the previous page.

注釈

もし前のページのサーバをまだ実行中である場合は、サーバを停止することも、このコマンドを新しい端末で実行することもできます。もし新しい端末を使用する場合は、プロジェクトのディレクトリへ移動して、環境を有効化(Activate the environment)で説明したように環境を有効にする(activate)ことを覚えておいてください。さらに、前のページで示したように、FLASK_APPFLASK_ENVの設定も必要です。 If you're still running the server from the previous page, you can either stop the server, or run this command in a new terminal. If you use a new terminal, remember to change to your project directory and activate the env as described in :ref:`install-activate-env`. You'll also need to set ``FLASK_APP`` and ``FLASK_ENV`` as shown on the previous page.

init-dbコマンドを実行: Run the ``init-db`` command:

$ flask init-db
Initialized the database.

この時点でプロジェクトのinstanceフォルダにflaskr.sqliteファイルがあるはずです。 There will now be a ``flaskr.sqlite`` file in the ``instance`` folder in your project.

青写真とビュー(Blueprints and Views)へ続きます。 Continue to :doc:`views`.