データベースの定義とアクセス
アプリケーションは、 SQLite データベースを使用してユーザーと投稿を保存します。 Pythonには、sqlite3
モジュールでSQLiteのサポートが組み込まれています。
SQLiteは、個別のデータベースサーバーを設定する必要がなく、Pythonに組み込まれているため、便利です。 ただし、同時リクエストが同時にデータベースに書き込もうとすると、各書き込みが順番に行われるため、速度が低下します。 小さなアプリケーションはこれに気づきません。 大きくなったら、別のデータベースに切り替えることをお勧めします。
チュートリアルでは、SQLについて詳しく説明していません。 よく知らない場合は、SQLiteのドキュメントで言語について説明しています。
データベースに接続する
SQLiteデータベース(および他のほとんどのPythonデータベースライブラリ)を操作するときに最初に行うことは、SQLiteデータベースへの接続を作成することです。 クエリと操作はすべて、作業が終了した後に閉じられる接続を使用して実行されます。
Webアプリケーションでは、この接続は通常、要求に関連付けられています。 リクエストを処理するときに作成され、レスポンスが送信される前に閉じられます。
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 は、リクエストごとに一意の特別なオブジェクトです。 これは、リクエスト中に複数の機能によってアクセスされる可能性のあるデータを格納するために使用されます。 同じリクエストでget_db
が2回呼び出された場合、接続は保存され、新しい接続を作成する代わりに再利用されます。
current_app は、リクエストを処理するFlaskアプリケーションを指すもう1つの特別なオブジェクトです。 アプリケーションファクトリを使用したため、残りのコードを記述するときにアプリケーションオブジェクトはありません。 get_db
は、アプリケーションが作成されてリクエストを処理しているときに呼び出されるため、 current_app を使用できます。
sqlite3.connect()
は、DATABASE
構成キーが指すファイルへの接続を確立します。 このファイルはまだ存在している必要はなく、後でデータベースを初期化するまで存在しません。
sqlite3.Row
は、dictのように動作する行を返すように接続に指示します。 これにより、名前で列にアクセスできます。
close_db
は、g.db
が設定されているかどうかを確認することにより、接続が作成されたかどうかを確認します。 接続が存在する場合、接続は閉じられます。 さらに下に、アプリケーションファクトリのclose_db
関数についてアプリケーションに通知し、各要求の後に呼び出されるようにします。
テーブルを作成する
SQLiteでは、データはテーブルおよび列に格納されます。 これらは、データを保存および取得する前に作成する必要があります。 Flaskrは、ユーザーをuser
テーブルに保存し、投稿をpost
テーブルに保存します。 空のテーブルを作成するために必要な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
ファイルに追加します。
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
は、ファイルから読み取られたコマンドを実行するために使用されるデータベース接続を返します。
click.command()
は、init_db
関数を呼び出し、ユーザーに成功メッセージを表示するinit-db
というコマンドラインコマンドを定義します。 コマンドラインインターフェイスを読んで、コマンドの記述について詳しく知ることができます。
アプリケーションに登録する
close_db
およびinit_db_command
関数は、アプリケーションインスタンスに登録する必要があります。 それ以外の場合は、アプリケーションで使用されません。 ただし、ファクトリ関数を使用しているため、関数を作成するときにそのインスタンスを使用することはできません。 代わりに、アプリケーションを取得して登録を行う関数を記述します。
def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
app.teardown_appcontext()
は、応答を返した後、クリーンアップするときにその関数を呼び出すようにFlaskに指示します。
app.cli.add_command()
は、flask
コマンドで呼び出すことができる新しいコマンドを追加します。
この関数を工場からインポートして呼び出します。 アプリを返す前に、ファクトリ関数の最後に新しいコードを配置します。
def create_app():
app = ...
# existing code omitted
from . import db
db.init_app(app)
return app
データベースファイルを初期化する
init-db
がアプリに登録されたので、前のページのrun
コマンドと同様に、flask
コマンドを使用して呼び出すことができます。
ノート
前のページからサーバーを実行している場合は、サーバーを停止するか、新しい端末でこのコマンドを実行できます。 新しい端末を使用する場合は、環境のアクティブ化の説明に従って、プロジェクトディレクトリに移動し、環境をアクティブ化することを忘れないでください。 また、前のページに示すように、FLASK_APP
とFLASK_ENV
を設定する必要があります。
init-db
コマンドを実行します。
flask init-db
Initialized the database.
これで、プロジェクトのinstance
フォルダーにflaskr.sqlite
ファイルが作成されます。
ブループリントとビューに進みます。