FlaskアプリケーションでPostgreSQLデータベースを使用する方法
著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。
序章
Webアプリケーションでは、通常、データの組織化されたコレクションであるデータベースが必要です。 データベースを使用して、効率的に取得および操作できる永続データを保存および維持します。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーデータ(個人情報、投稿、コメント、フォロワー)が効率的に操作できる方法で保存されているデータベースがあります。 さまざまな要件や条件に応じて、データベースにデータを追加、取得、変更、または削除できます。 Webアプリケーションでは、これらの要件は、ユーザーが新しい投稿を追加したり、投稿を削除したり、アカウントを削除したりする場合があります。これにより、投稿が削除される場合と削除されない場合があります。 データを操作するために実行するアクションは、アプリケーションの特定の機能によって異なります。 たとえば、タイトルのない投稿をユーザーに追加させたくない場合があります。
Flaskは、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 PostgreSQL 、またはPostgresは、SQLクエリ言語の実装を提供するリレーショナルデータベース管理システムです。 これは標準に準拠しており、信頼性の高いトランザクションや読み取りロックのない同時実行性など、多くの高度な機能を備えています。
このチュートリアルでは、PythonでPostgreSQLデータベースを操作できるPostgreSQLデータベースアダプタであるpsycopg2ライブラリの使用方法を示す小さな書評Webアプリケーションを作成します。 これをFlaskで使用して、データベースサーバーへの接続、テーブルの作成、テーブルへのデータの挿入、テーブルからのデータの取得などの基本的なタスクを実行します。
前提条件
- ローカルのPython3プログラミング環境。 Python3シリーズのローカルプログラミング環境をインストールおよびセットアップする方法のチュートリアルに従ってください。 このチュートリアルでは、プロジェクトディレクトリは
flask_app
と呼ばれます。 - ルート、ビュー関数、テンプレートなどの基本的なFlaskの概念の理解。 Flaskに慣れていない場合は、FlaskとPythonを使用して最初のWebアプリケーションを作成する方法およびFlaskアプリケーションでテンプレートを使用する方法を確認してください。
- 基本的なHTMLの概念の理解。 背景知識については、HTMLを使用してWebサイトを構築する方法チュートリアルシリーズを確認できます。
- ローカルマシンにPostgreSQLがインストールされており、PostgreSQLプロンプトにアクセスします。 Ubuntu 20.04にPostgreSQLをインストールして使用する方法に従って、PostgreSQLデータベースをセットアップします。
ステップ1—PostgreSQLデータベースとユーザーの作成
このステップでは、Flaskアプリケーション用にflask_db
というデータベースとsammy
というデータベースユーザーを作成します。
Postgresのインストール中に、postgres
という名前のオペレーティングシステムユーザーが、postgres
PostgreSQL管理ユーザーに対応するように作成されました。 管理タスクを実行するには、このユーザーを使用する必要があります。 sudo
を使用して、-iu
オプションを使用してユーザー名を渡すことができます。
次のコマンドを使用して、インタラクティブなPostgresセッションにログインします。
sudo -iu postgres psql
要件を設定できるPostgreSQLプロンプトが表示されます。
まず、プロジェクトのデータベースを作成します。
CREATE DATABASE flask_db;
注:すべてのPostgresステートメントはセミコロンで終了する必要があるため、問題が発生している場合は、コマンドがセミコロンで終了していることを確認してください。
次に、プロジェクトのデータベースユーザーを作成します。 安全なパスワードを選択してください。
CREATE USER sammy WITH PASSWORD 'password';
次に、この新しいユーザーに新しいデータベースを管理するためのアクセス権を付与します。
GRANT ALL PRIVILEGES ON DATABASE flask_db TO sammy;
データベースが作成されたことを確認するには、次のコマンドを入力してデータベースのリストを取得します。
\l
データベースのリストにflask_db
が表示されます。
終了したら、次のように入力してPostgreSQLプロンプトを終了します。
\q
これで、Postgresがセットアップされ、psycopg2
ライブラリを使用してPython経由でデータベース情報に接続して管理できるようになりました。 次に、このライブラリをFlaskパッケージと一緒にインストールします。
ステップ2—Flaskとpsycopg2をインストールする
このステップでは、Flaskとpsycopg2
ライブラリをインストールして、Pythonを使用してデータベースを操作できるようにします。
仮想環境をアクティブにした状態で、pip
を使用してFlaskとpsycopg2
ライブラリをインストールします。
pip install Flask psycopg2-binary
インストールが正常に完了すると、出力の最後に次のような行が表示されます。
Output Successfully installed Flask-2.0.2 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1 psycopg2-binary-2.9.2
これで、必要なパッケージが仮想環境にインストールされました。 次に、データベースに接続してセットアップします。
ステップ3—データベースのセットアップ
このステップでは、flask_app
プロジェクトディレクトリにPythonファイルを作成して、flask_db
データベースに接続し、書籍を保存するためのテーブルを作成し、レビュー付きの書籍を挿入します。
まず、プログラミング環境をアクティブにして、flask_app
ディレクトリにあるinit_db.py
という新しいファイルを開きます。
nano init_db.py
このファイルは、flask_db
データベースへの接続を開き、books
というテーブルを作成し、サンプルデータを使用してテーブルにデータを入力します。 次のコードを追加します。
フラスコ_app/init_db.py
import os import psycopg2 conn = psycopg2.connect( host="localhost", database="flask_db", user=os.environ['DB_USERNAME'], password=os.environ['DB_PASSWORD']) # Open a cursor to perform database operations cur = conn.cursor() # Execute a command: this creates a new table cur.execute('DROP TABLE IF EXISTS books;') cur.execute('CREATE TABLE books (id serial PRIMARY KEY,' 'title varchar (150) NOT NULL,' 'author varchar (50) NOT NULL,' 'pages_num integer NOT NULL,' 'review text,' 'date_added date DEFAULT CURRENT_TIMESTAMP);' ) # Insert data into the table cur.execute('INSERT INTO books (title, author, pages_num, review)' 'VALUES (%s, %s, %s, %s)', ('A Tale of Two Cities', 'Charles Dickens', 489, 'A great classic!') ) cur.execute('INSERT INTO books (title, author, pages_num, review)' 'VALUES (%s, %s, %s, %s)', ('Anna Karenina', 'Leo Tolstoy', 864, 'Another great classic!') ) conn.commit() cur.close() conn.close()
ファイルを保存して閉じます。
このファイルでは、最初に os モジュールをインポートして、データベースのユーザー名とパスワードを保存する環境変数にアクセスし、ソースコードに表示されないようにします。
psycopg2
ライブラリをインポートします。 次に、psycopg2.connect()
関数を使用して、flask_db
データベースへの接続を開きます。 ホストを指定します。この場合はローカルホストです。 データベース名をdatabase
パラメーターに渡します。
os.environ
オブジェクトを介してユーザー名とパスワードを指定します。これにより、プログラミング環境で設定した環境変数にアクセスできます。 データベースのユーザー名はDB_USERNAME
という環境変数に保存し、パスワードはDB_PASSWORD
という環境変数に保存します。 これにより、ユーザー名とパスワードをソースコードの外部に保存できるため、ソースコードをソース管理に保存したり、インターネット上のサーバーにアップロードしたりするときに機密情報が漏洩することはありません。 攻撃者がソースコードにアクセスしたとしても、データベースにアクセスすることはできません。
connection.cursor()メソッドを使用して、cur
というカーソルを作成します。これにより、PythonコードでデータベースセッションでPostgreSQLコマンドを実行できます。
カーソルのexecute()
メソッドを使用して、books
テーブルがすでに存在する場合は削除します。 これにより、books
という名前の別のテーブルが存在する可能性が回避され、混乱を招く動作が発生する可能性があります(たとえば、列が異なる場合)。 テーブルをまだ作成していないため、SQLコマンドは実行されないため、ここでは当てはまりません。 このinit_db.py
ファイルを実行すると、既存のデータがすべて削除されることに注意してください。 この目的のために、データベースを開始するためにこのファイルを1回だけ実行しますが、挿入したデータを削除して最初のサンプルデータからやり直すために、もう一度実行することをお勧めします。
次に、CREATE TABLE books
を使用して、次の列を持つbooks
という名前のテーブルを作成します。
id
:自動インクリメント整数であるserial
タイプのID。 この列は、PRIMARY KEY
キーワードを使用して指定した主キーを表します。 データベースは、エントリごとにこのキーに一意の値を割り当てます。title
:varchar
タイプの本のタイトルで、制限付きの可変長の文字タイプです。varchar (150)
は、タイトルの長さが最大150文字であることを意味します。NOT NULL
は、この列を空にすることはできないことを示します。author
:本の著者。制限は50文字です。NOT NULL
は、この列を空にすることはできないことを示します。pages_num
:本のページ数を表す整数。NOT NULL
は、この列を空にすることはできないことを示します。review
:書評。text
タイプは、レビューを任意の長さのテキストにすることができることを意味します。date_added
:本がテーブルに追加された日付。DEFAULT
は、列のデフォルト値をCURRENT_TIMESTAMP
に設定します。これは、書籍がデータベースに追加された時刻です。id
と同様に、この列の値は自動的に入力されるため、指定する必要はありません。
テーブルを作成したら、カーソルのexecute()
メソッドを使用して、2冊の本をテーブルに挿入します。チャールズディケンズの二都物語と、レオのアンナカレーニナです。トルストイ。 %s
プレースホルダーを使用して、SQLステートメントに値を渡します。 psycopg2
は、SQLインジェクション攻撃を防ぐ方法でバックグラウンドでの挿入を処理します。
書籍データをテーブルに挿入し終えたら、 connection.commit()メソッドを使用してトランザクションをコミットし、変更をデータベースに適用します。 次に、cur.close()
でカーソルを閉じ、conn.close()
で接続してクリーンアップします。
データベース接続を確立するには、次のコマンドを実行して、DB_USERNAME
およびDB_PASSWORD
環境変数を設定します。 自分のユーザー名とパスワードを使用することを忘れないでください。
export DB_USERNAME="sammy" export DB_PASSWORD="password"
次に、python
コマンドを使用して、ターミナルでinit_db.py
ファイルを実行します。
python init_db.py
ファイルがエラーなしで実行を終了すると、新しいbooks
テーブルがflask_db
データベースに追加されます。
インタラクティブなPostgresセッションにログインして、新しいbooks
テーブルをチェックアウトします。
sudo -iu postgres psql
\c
コマンドを使用して、flask_db
データベースに接続します。
\c flask_db
次に、SELECT
ステートメントを使用して、books
テーブルから本のタイトルと著者を取得します。
SELECT title, author FROM books;
次のような出力が表示されます。
title | author ----------------------+------------------ A Tale of Two Cities | Charles Dickens Anna Karenina | Leo Tolstoy
\q
でインタラクティブセッションを終了します。
次に、小さなFlaskアプリケーションを作成し、データベースに接続して、データベースに挿入した2つの書評を取得し、それらをインデックスページに表示します。
ステップ4—本を表示する
このステップでは、データベースにある本を取得して表示するインデックスページを使用してFlaskアプリケーションを作成します。
プログラミング環境をアクティブにしてFlaskをインストールしたら、flask_app
ディレクトリ内で編集するためにapp.py
というファイルを開きます。
nano app.py
このファイルはデータベース接続をセットアップし、その接続を使用する単一のFlaskルートを作成します。 次のコードをファイルに追加します。
フラスコ_app/app.py
import os import psycopg2 from flask import Flask, render_template app = Flask(__name__) def get_db_connection(): conn = psycopg2.connect(host='localhost', database='flask_db', user=os.environ['DB_USERNAME'], password=os.environ['DB_PASSWORD']) return conn @app.route('/') def index(): conn = get_db_connection() cur = conn.cursor() cur.execute('SELECT * FROM books;') books = cur.fetchall() cur.close() conn.close() return render_template('index.html', books=books)
ファイルを保存して閉じます。
ここでは、os
モジュール、psycopg2
ライブラリ、Flask
クラス、およびrender_template()
をflask
パッケージからインポートします。 app
というFlaskアプリケーションインスタンスを作成します。
get_db_connection()
という関数を定義します。この関数は、DB_USERNAME
およびDB_PASSWORD
環境変数に保存したユーザーとパスワードを使用してflask_db
データベースへの接続を開きます。 この関数は、データベースへのアクセスに使用するconn
接続オブジェクトを返します。
次に、app.route()
デコレータを使用して、メインの/
ルートとindex()
ビュー関数を作成します。 index()
ビュー関数では、get_db_connection()
関数を使用してデータベース接続を開き、カーソルを作成し、SELECT * FROM books;
SQLステートメントを実行して、データベース。 fetchall()
メソッドを使用して、books
という変数にデータを保存します。 次に、カーソルと接続を閉じます。 最後に、render_template()
関数の呼び出しを返し、index.html
というテンプレートファイルをレンダリングして、データベースからフェッチした書籍のリストをbooks
変数に渡します。
データベースにある本をインデックスページに表示するには、最初にベーステンプレートを作成します。このテンプレートには、コードの繰り返しを避けるために他のテンプレートでも使用されるすべての基本的なHTMLコードが含まれます。 次に、index()
関数でレンダリングしたindex.html
テンプレートファイルを作成します。 テンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。
templates
ディレクトリを作成し、base.html
という名前の新しいテンプレートを開きます。
mkdir templates nano templates/base.html
base.html
ファイル内に次のコードを追加します。
フラスコ_app/templates / base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %} {% endblock %}- FlaskApp</title> <style> nav a { color: #d64161; font-size: 3em; margin-left: 50px; text-decoration: none; } .book { padding: 20px; margin: 10px; background-color: #f7f4f4; } .review { margin-left: 50px; font-size: 20px; } </style> </head> <body> <nav> <a href="{{ url_for('index') }}">FlaskApp</a> <a href="#">About</a> </nav> <hr> <div class="content"> {% block content %} {% endblock %} </div> </body> </html>
ファイルを保存して閉じます。
この基本テンプレートには、他のテンプレートで再利用する必要があるすべてのHTMLボイラープレートが含まれています。 title
ブロックは各ページのタイトルを設定するために置き換えられ、content
ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには2つのリンクがあります。1つはurl_for()
ヘルパー機能を使用してindex()
ビュー機能にリンクするインデックスページ用で、もう1つはAboutページ用です。アプリケーションに含めることを選択した場合。
次に、index.html
というテンプレートを開きます。 これは、app.py
ファイルで参照したテンプレートです。
nano templates/index.html
次のコードを追加します。
フラスコ_app/templates / index.html
{% extends 'base.html' %} {% block content %} <h1>{% block title %} Books {% endblock %}</h1> {% for book in books %} <div class='book'> <h3>#{{ book[0] }} - {{ book[1] }} BY {{ book[2] }}</h3> <i><p>({{ book[3] }} pages)</p></i> <p class='review'>{{ book[4] }}</p> <i><p>Added {{ book[5] }}</p></i> </div> {% endfor %} {% endblock %}
ファイルを保存して閉じます。
このファイルでは、ベーステンプレートを拡張し、content
ブロックの内容を置き換えます。 タイトルを兼ねる<h1>
の見出しを使用します。
{% for book in books %}
行のJinjafor loop を使用して、books
リストの各本を調べます。 book[0]
を使用して最初のアイテムであるブックIDを表示します。 次に、本のタイトル、著者、ページ数、レビュー、および本が追加された日付を表示します。
仮想環境をアクティブにしてflask_app
ディレクトリにいるときに、FLASK_APP
環境変数を使用して、アプリケーション(この場合はapp.py
)についてFlaskに通知します。 次に、FLASK_ENV
環境変数をdevelopment
に設定して、アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します。
export FLASK_APP=app export FLASK_ENV=development
DB_USERNAME
およびDB_PASSWORD
環境変数をまだ設定していない場合は、必ず設定してください。
export DB_USERNAME="sammy" export DB_PASSWORD="password"
次に、アプリケーションを実行します。
flask run
開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。
http://127.0.0.1:5000/
最初の開始時にデータベースに追加した本が表示されます。
データベース内の書籍をインデックスページに表示しました。 ここで、ユーザーが新しい本を追加できるようにする必要があります。 次のステップで、本を追加するための新しいルートを追加します。
ステップ5—新しい本を追加する
このステップでは、データベースに新しい本やレビューを追加するための新しいルートを作成します。
ユーザーが本のタイトル、本の著者、ページ数、書評を入力するWebフォームを含むページを追加します。
開発サーバーを実行したままにして、新しいターミナルウィンドウを開きます。
まず、app.py
ファイルを開きます。
nano app.py
Webフォームを処理するには、flask
パッケージからいくつかのものをインポートする必要があります。
- 送信されたデータにアクセスするためのグローバルrequestオブジェクト。
- url_for()関数を使用してURLを生成します。
- redirect()関数は、データベースに本を追加した後、ユーザーをインデックスページにリダイレクトします。
これらのインポートをファイルの最初の行に追加します。
フラスコ_app/app.py
from flask import Flask, render_template, request, url_for, redirect # ...
次に、app.py
ファイルの最後に次のルートを追加します。
フラスコ_app/app.py
# ... @app.route('/create/', methods=('GET', 'POST')) def create(): return render_template('create.html')
ファイルを保存して閉じます。
このルートでは、タプル('GET', 'POST')
をmethods
パラメーターに渡して、GET要求とPOST要求の両方を許可します。 GETリクエストは、サーバーからデータを取得するために使用されます。 POSTリクエストは、特定のルートにデータを投稿するために使用されます。 デフォルトでは、GETリクエストのみが許可されます。 ユーザーが最初にGETリクエストを使用して/create
ルートをリクエストすると、create.html
というテンプレートファイルがレンダリングされます。 後でこのルートを編集して、ユーザーが新しい本を追加するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。
新しいcreate.html
テンプレートを開きます。
nano templates/create.html
次のコードを追加します。
フラスコ_app/templates / create.html
{% extends 'base.html' %} {% block content %} <h1>{% block title %} Add a New Book {% endblock %}</h1> <form method="post"> <p> <label for="title">Title</label> <input type="text" name="title" placeholder="Book title"> </input> </p> <p> <label for="author">Author</label> <input type="text" name="author" placeholder="Book author"> </input> </p> <p> <label for="pages_num">Number of pages</label> <input type="number" name="pages_num" placeholder="Number of pages"> </input> </p> <p> <label for="review">Review</label> <br> <textarea name="review" placeholder="Review" rows="15" cols="60" ></textarea> </p> <p> <button type="submit">Submit</button> </p> </form> {% endblock %}
ファイルを保存して閉じます。
基本テンプレートを拡張し、見出しをタイトルとして設定し、属性method
をpost
に設定した<form>
タグを使用して、フォームがPOSTリクエストを送信することを示します。
title
という名前のテキストフィールドがあり、これを使用して/create
ルートのタイトルデータにアクセスします。
著者用のテキストフィールド、ページ数用の番号フィールド、および書評用のテキスト領域があります。
最後に、フォームの最後に送信ボタンがあります。
これで、開発サーバーが実行されている状態で、ブラウザーを使用して/create
ルートに移動します。
http://127.0.0.1:5000/create
新しい本を追加ページが表示されます。このページには、本のタイトル、著者、ページ数の入力フィールド、本のレビュー用のテキスト領域、および送信ボタン。
フォームに入力して送信し、サーバーにPOSTリクエストを送信しても、/create
ルートでPOSTリクエストを処理しなかったため、何も起こりません。
app.py
を開いて、ユーザーが送信するPOST要求を処理します。
nano app.py
/create
ルートを編集して、次のようにします。
フラスコ_app/app.py
# ... @app.route('/create/', methods=('GET', 'POST')) def create(): if request.method == 'POST': title = request.form['title'] author = request.form['author'] pages_num = int(request.form['pages_num']) review = request.form['review'] conn = get_db_connection() cur = conn.cursor() cur.execute('INSERT INTO books (title, author, pages_num, review)' 'VALUES (%s, %s, %s, %s)', (title, author, pages_num, review)) conn.commit() cur.close() conn.close() return redirect(url_for('index')) return render_template('create.html')
ファイルを保存して閉じます。
if request.method == 'POST'
条件内でPOST要求を処理します。 request.form
オブジェクトから、タイトル、作成者、ページ数、およびユーザーが送信したレビューを抽出します。
get_db_connection()
関数を使用してデータベースを開き、カーソルを作成します。 次に、INSERT INTO
SQLステートメントを実行して、タイトル、作成者、ページ数を挿入し、books
テーブルに送信されたユーザーを確認します。
トランザクションをコミットし、カーソルと接続を閉じます。
最後に、ユーザーをインデックスページにリダイレクトします。このページでは、既存の本の下に新しく追加された本が表示されます。
開発サーバーが実行されている状態で、ブラウザーを使用して/create
ルートに移動します。
http://127.0.0.1:5000/create
フォームにデータを入力して送信します。
新しい書評が表示されるインデックスページにリダイレクトされます。
次に、ナビゲーションバーの[作成]ページへのリンクを追加します。 base.html
を開きます:
nano templates/base.html
次のようにファイルを編集します。
フラスコ_app/templates / base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %} {% endblock %} - FlaskApp</title> <style> nav a { color: #d64161; font-size: 3em; margin-left: 50px; text-decoration: none; } .book { padding: 20px; margin: 10px; background-color: #f7f4f4; } .review { margin-left: 50px; font-size: 20px; } </style> </head> <body> <nav> <a href="{{ url_for('index') }}">FlaskApp</a> <a href="{{ url_for('create') }}">Create</a> <a href="#">About</a> </nav> <hr> <div class="content"> {% block content %} {% endblock %} </div> </body> </html>
ファイルを保存して閉じます。
ここでは、作成ページを指すナビゲーションバーに新しい<a>
リンクを追加します。
インデックスページを更新すると、ナビゲーションバーに新しいリンクが表示されます。
これで、新しい書評を追加するためのWebフォームを含むページができました。 Webフォームの詳細については、FlaskアプリケーションでWebフォームを使用する方法を参照してください。 Webフォームを管理するためのより高度で安全な方法については、Flask-WTFを使用してWebフォームを使用および検証する方法を参照してください。
結論
PostgreSQLデータベースと通信する書評用の小さなWebアプリケーションを作成しました。 Flaskアプリケーションには、データベースへの新しいデータの追加、データの取得、ページへの表示など、基本的なデータベース機能があります。
Flaskの詳細については、Flaskシリーズの他のチュートリアルをご覧ください。