FlaskアプリケーションでPostgreSQLデータベースを使用する方法
序章
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_db
およびと呼ばれるデータベースユーザー sammy
Flaskアプリケーション用。
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がセットアップされ、Pythonを介してデータベース情報に接続して管理できるようになりました。 psycopg2
図書館。 次に、このライブラリを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—データベースのセットアップ
このステップでは、Pythonファイルを作成します flask_app
接続するプロジェクトディレクトリ flask_db
データベースを作成し、本を保存するためのテーブルを作成し、レビュー付きの本をいくつか挿入します。
まず、プログラミング環境をアクティブにして、という新しいファイルを開きます。 init_db.py
あなたの中で flask_app
ディレクトリ。
- nano init_db.py
このファイルは、への接続を開きます flask_db
データベース、というテーブルを作成します books
、サンプルデータを使用してテーブルにデータを入力します。 次のコードを追加します。
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
図書館。 次に、への接続を開きます flask_db
を使用したデータベース psycopg2.connect()
関数。 ホストを指定します。この場合はローカルホストです。 データベース名をに渡します database
パラメータ。
ユーザー名とパスワードは、 os.environ
オブジェクト。プログラミング環境で設定した環境変数にアクセスできます。 データベースのユーザー名をという環境変数に保存します DB_USERNAME
およびと呼ばれる環境変数のパスワード DB_PASSWORD
. これにより、ユーザー名とパスワードをソースコードの外部に保存できるため、ソースコードをソース管理に保存したり、インターネット上のサーバーにアップロードしたりするときに機密情報が漏洩することはありません。 攻撃者がソースコードにアクセスしたとしても、データベースにアクセスすることはできません。
と呼ばれるカーソルを作成します cur
connection.cursor()メソッドを使用します。これにより、PythonコードがデータベースセッションでPostgreSQLコマンドを実行できるようになります。
カーソルを使用します execute()
を削除する方法 books
すでに存在する場合はテーブル。 これにより、という名前の別のテーブルの可能性が回避されます books
既存の場合、混乱する動作が発生する可能性があります(たとえば、列が異なる場合)。 テーブルをまだ作成していないため、SQLコマンドは実行されないため、ここでは当てはまりません。 これを実行すると、既存のデータがすべて削除されることに注意してください init_db.py
ファイル。 この目的のために、データベースを開始するためにこのファイルを1回だけ実行しますが、挿入したデータを削除して最初のサンプルデータからやり直すために、もう一度実行することをお勧めします。
次に、 CREATE TABLE books
名前の付いたテーブルを作成するには books
次の列を使用します。
id
:のIDserial
タイプ。これは自動インクリメント整数です。 この列は、を使用して指定した主キーを表します。PRIMARY KEY
キーワード。 データベースは、エントリごとにこのキーに一意の値を割り当てます。title
:本のタイトルvarchar
typeは、制限付きの可変長の文字タイプです。varchar (150)
タイトルの長さは最大150文字であることを意味します。NOT NULL
この列を空にすることはできないことを意味します。author
:本の著者、50文字まで。NOT NULL
この列を空にすることはできないことを意味します。pages_num
:本のページ数を表す整数。NOT NULL
この列を空にすることはできないことを意味します。review
:書評。 Thetext
タイプは、レビューが任意の長さのテキストであることを意味します。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"
今、あなたを実行します init_db.py
を使用してターミナルでファイル python
指図:
- python init_db.py
ファイルがエラーなしで実行を終了すると、新しい books
テーブルがあなたに追加されます flask_db
データベース。
インタラクティブなPostgresセッションにログインして、新しいをチェックアウトします books
テーブル。
- sudo -iu postgres psql
に接続します flask_db
を使用したデータベース \c
指図:
- \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をインストールした状態で、次のファイルを開きます。 app.py
あなたの中で編集するため flask_app
ディレクトリ:
- nano app.py
このファイルはデータベース接続をセットアップし、その接続を使用する単一のFlaskルートを作成します。 次のコードをファイルに追加します。
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
パッケージ。 と呼ばれるFlaskアプリケーションインスタンスを作成します app
.
と呼ばれる関数を定義します get_db_connection()
、への接続を開きます flask_db
保存したユーザーとパスワードを使用したデータベース DB_USERNAME
と DB_PASSWORD
環境変数。 関数は conn
データベースへのアクセスに使用する接続オブジェクト。
次に、メインを作成します /
ルートと index()
を使用した表示機能 app.route()
デコレータ。 の中に index()
ビュー機能では、データベース接続を使用してデータベース接続を開きます get_db_connection()
関数、カーソルを作成し、実行します SELECT * FROM books;
データベースにあるすべての本を取得するSQLステートメント。 あなたは fetchall()
と呼ばれる変数にデータを保存するメソッド books
. 次に、カーソルと接続を閉じます。 最後に、 render_template()
と呼ばれるテンプレートファイルをレンダリングする関数 index.html
データベースからフェッチした本のリストを books
変数。
データベースにある本をインデックスページに表示するには、最初にベーステンプレートを作成します。このテンプレートには、コードの繰り返しを避けるために他のテンプレートでも使用されるすべての基本的なHTMLコードが含まれます。 次に、を作成します index.html
レンダリングしたテンプレートファイル index()
関数。 テンプレートの詳細については、Flaskアプリケーションでテンプレートを使用する方法を参照してください。
作成する templates
ディレクトリ、次にという名前の新しいテンプレートを開きます base.html
:
- mkdir templates
- nano templates/base.html
内に次のコードを追加します 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ボイラープレートが含まれています。 The title
各ページのタイトルを設定するためにブロックが置き換えられ、 content
ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには2つのリンクがあります。1つは、を使用するインデックスページ用です。 url_for()
リンクするヘルパー関数 index()
ビュー機能、およびアプリケーションに1つを含めることを選択した場合は、Aboutページ用のもう1つ。
次に、というテンプレートを開きます index.html
. これは、で参照したテンプレートです。 app.py
ファイル:
- nano 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>
タイトルを兼ねる見出し。
行でJinjaforloopを使用します {% for book in books %}
の各本を読む books
リスト。 を使用して最初のアイテムであるブックIDを表示します book[0]
. 次に、本のタイトル、著者、ページ数、レビュー、および本が追加された日付を表示します。
あなたの中に flask_app
仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py
この場合)を使用して FLASK_APP
環境変数。 次に、 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()関数は、データベースに本を追加した後、ユーザーをインデックスページにリダイレクトします。
これらのインポートをファイルの最初の行に追加します。
from flask import Flask, render_template, request, url_for, redirect
# ...
次に、最後に次のルートを追加します app.py
ファイル:
# ...
@app.route('/create/', methods=('GET', 'POST'))
def create():
return render_template('create.html')
ファイルを保存して閉じます。
このルートでは、タプルを渡します ('GET', 'POST')
に methods
GET要求とPOST要求の両方を許可するパラメーター。 GETリクエストは、サーバーからデータを取得するために使用されます。 POSTリクエストは、特定のルートにデータを投稿するために使用されます。 デフォルトでは、GETリクエストのみが許可されます。 ユーザーが最初にリクエストしたとき /create
GETリクエストを使用してルーティングします。 create.html
レンダリングされます。 後でこのルートを編集して、ユーザーが新しい本を追加するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。
新しいを開く create.html
テンプレート:
- nano 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 %}
ファイルを保存して閉じます。
基本テンプレートを拡張し、見出しをタイトルとして設定し、 <form>
属性を持つタグ method
に設定 post
フォームがPOSTリクエストを送信することを示します。
名前の付いたテキストフィールドがあります title
、のタイトルデータにアクセスするために使用します /create
ルート。
著者用のテキストフィールド、ページ数用の番号フィールド、および書評用のテキスト領域があります。
最後に、フォームの最後に送信ボタンがあります。
これで、開発サーバーが実行されている状態で、ブラウザーを使用してに移動します。 /create
ルート:
http://127.0.0.1:5000/create
新しい本を追加ページが表示されます。このページには、本のタイトル、著者、ページ数の入力フィールド、本のレビュー用のテキスト領域、および送信ボタン。
フォームに入力して送信し、サーバーにPOSTリクエストを送信すると、POSTリクエストを処理しなかったため、何も起こりません。 /create
ルート。
開ける app.py
ユーザーが送信するPOSTリクエストを処理するには:
- nano app.py
編集します /create
次のように見えるルート:
# ...
@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')
ファイルを保存して閉じます。
POSTリクエストは内部で処理します if request.method == 'POST'
調子。 タイトル、作成者、ページ数、およびユーザーが送信したレビューを request.form
物体。
を使用してデータベースを開きます get_db_connection()
関数、およびカーソルを作成します。 次に、を実行します INSERT INTO
タイトル、作成者、ページ数を挿入し、に送信されたユーザーを確認するSQLステートメント books
テーブル。
トランザクションをコミットし、カーソルと接続を閉じます。
最後に、ユーザーをインデックスページにリダイレクトします。このページでは、既存の本の下に新しく追加された本が表示されます。
開発サーバーが実行されている状態で、ブラウザを使用してに移動します /create
ルート:
http://127.0.0.1:5000/create
フォームにデータを入力して送信します。
新しい書評が表示されるインデックスページにリダイレクトされます。
次に、ナビゲーションバーの[作成]ページへのリンクを追加します。 開ける base.html
:
- nano 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シリーズの他のチュートリアルをご覧ください。