序章

Webアプリケーションでは、通常、データの組織化されたコレクションであるデータベースが必要です。 データベースを使用して、効率的に取得および操作できる永続データを保存および維持します。 たとえば、ソーシャルメディアアプリケーションでは、ユーザーデータ(個人情報、投稿、コメント、フォロワー)が効率的に操作できる方法で保存されているデータベースがあります。 さまざまな要件や条件に応じて、データベースにデータを追加、取得、変更、または削除できます。 Webアプリケーションでは、これらの要件は、ユーザーが新しい投稿を追加したり、投稿を削除したり、アカウントを削除したりする場合があります。これにより、投稿が削除される場合と削除されない場合があります。 データを操作するために実行するアクションは、アプリケーションの特定の機能によって異なります。 たとえば、タイトルのない投稿をユーザーに追加させたくない場合があります。

Flaskは、Python言語でWebアプリケーションを作成するための便利なツールと機能を提供する軽量のPythonWebフレームワークです。 PostgreSQL 、またはPostgresは、SQLクエリ言語の実装を提供するリレーショナルデータベース管理システムです。 これは標準に準拠しており、信頼性の高いトランザクションや読み取りロックのない同時実行性など、多くの高度な機能を備えています。

このチュートリアルでは、PythonでPostgreSQLデータベースを操作できるPostgreSQLデータベースアダプターであるpsycopg2ライブラリの使用方法を示す小さな本のレビューWebアプリケーションを作成します。 これをFlaskで使用して、データベースサーバーへの接続、テーブルの作成、テーブルへのデータの挿入、テーブルからのデータの取得などの基本的なタスクを実行します。

前提条件

ステップ1—PostgreSQLデータベースとユーザーの作成

このステップでは、というデータベースを作成します flask_db およびと呼ばれるデータベースユーザー sammy Flaskアプリケーション用。

Postgresのインストール中に、 postgres に対応するために作成されました postgres PostgreSQL管理ユーザー。 管理タスクを実行するには、このユーザーを使用する必要があります。 使用できます sudo そして、ユーザー名を -iu オプション。

次のコマンドを使用して、インタラクティブなPostgresセッションにログインします。

  1. sudo -iu postgres psql

要件を設定できるPostgreSQLプロンプトが表示されます。

まず、プロジェクトのデータベースを作成します。

  1. CREATE DATABASE flask_db;

注:すべてのPostgresステートメントはセミコロンで終了する必要があるため、問題が発生している場合は、コマンドがセミコロンで終了していることを確認してください。

次に、プロジェクトのデータベースユーザーを作成します。 安全なパスワードを選択してください。

  1. CREATE USER sammy WITH PASSWORD 'password';

次に、この新しいユーザーに新しいデータベースを管理するためのアクセス権を付与します。

  1. GRANT ALL PRIVILEGES ON DATABASE flask_db TO sammy;

データベースが作成されたことを確認するには、次のコマンドを入力してデータベースのリストを取得します。

  1. \l

わかるでしょ flask_db データベースのリストにあります。

終了したら、次のように入力してPostgreSQLプロンプトを終了します。

  1. \q

これで、Postgresがセットアップされ、Pythonを介してデータベース情報に接続して管理できるようになりました。 psycopg2 図書館。 次に、このライブラリをFlaskパッケージと一緒にインストールします。

ステップ2—Flaskとpsycopg2をインストールする

このステップでは、Flaskと psycopg2 Pythonを使用してデータベースを操作できるようにするためのライブラリ。

仮想環境をアクティブにして、 pip Flaskとをインストールするには psycopg2 図書館:

  1. 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 ディレクトリ。

  1. 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 図書館。 次に、への接続を開きます 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:のID serial タイプ。これは自動インクリメント整数です。 この列は、を使用して指定した主キーを表します。 PRIMARY KEY キーワード。 データベースは、エントリごとにこのキーに一意の値を割り当てます。
  • title:本のタイトル varchar typeは、制限付きの可変長の文字タイプです。 varchar (150) タイトルの長さは最大150文字であることを意味します。 NOT NULL この列を空にすることはできないことを意味します。
  • author:本の著者、50文字まで。 NOT NULL この列を空にすることはできないことを意味します。
  • pages_num:本のページ数を表す整数。 NOT NULL この列を空にすることはできないことを意味します。
  • review:書評。 The text タイプは、レビューが任意の長さのテキストであることを意味します。
  • date_added:本がテーブルに追加された日付。 DEFAULT 列のデフォルト値をに設定します CURRENT_TIMESTAMP、これは本がデータベースに追加された時刻です。 と同じように id、この列の値は自動的に入力されるため、指定する必要はありません。

テーブルを作成した後、カーソルのを使用します execute() テーブルに2冊の本を挿入する方法。チャールズ・ディケンズの二都物語と、レオ・トルストイのアンナ・カレーニナ。 あなたは %s SQLステートメントに値を渡すためのプレースホルダー。 psycopg2 SQLインジェクション攻撃を防ぐ方法でバックグラウンドでの挿入を処理します。

書籍データをテーブルに挿入し終えたら、 connection.commit()メソッドを使用してトランザクションをコミットし、変更をデータベースに適用します。 次に、カーソルを閉じてクリーンアップします。 cur.close()、およびとの接続 conn.close().

データベース接続を確立するには、 DB_USERNAMEDB_PASSWORD 次のコマンドを実行して環境変数を設定します。 自分のユーザー名とパスワードを使用することを忘れないでください。

  1. export DB_USERNAME="sammy"
  2. export DB_PASSWORD="password"

今、あなたを実行します init_db.py を使用してターミナルでファイル python 指図:

  1. python init_db.py

ファイルがエラーなしで実行を終了すると、新しい books テーブルがあなたに追加されます flask_db データベース。

インタラクティブなPostgresセッションにログインして、新しいをチェックアウトします books テーブル。

  1. sudo -iu postgres psql

に接続します flask_db を使用したデータベース \c 指図:

  1. \c flask_db

次に、 SELECT から本のタイトルと著者を取得するためのステートメント books テーブル:

  1. 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 ディレクトリ:

  1. 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 パッケージ。 と呼ばれるFlaskアプリケーションインスタンスを作成します app.

と呼ばれる関数を定義します get_db_connection()、への接続を開きます flask_db 保存したユーザーとパスワードを使用したデータベース DB_USERNAMEDB_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:

  1. mkdir templates
  2. 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ボイラープレートが含まれています。 The title 各ページのタイトルを設定するためにブロックが置き換えられ、 content ブロックは各ページのコンテンツに置き換えられます。 ナビゲーションバーには2つのリンクがあります。1つは、を使用するインデックスページ用です。 url_for() リンクするヘルパー関数 index() ビュー機能、およびアプリケーションに1つを含めることを選択した場合は、Aboutページ用のもう1つ。

次に、というテンプレートを開きます index.html. これは、で参照したテンプレートです。 app.py ファイル:

  1. 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> タイトルを兼ねる見出し。

行でJinjaforloopを使用します {% for book in books %} の各本を読む books リスト。 を使用して最初のアイテムであるブックIDを表示します book[0]. 次に、本のタイトル、著者、ページ数、レビュー、および本が追加された日付を表示します。

あなたの中に flask_app 仮想環境がアクティブ化されているディレクトリ、アプリケーションについてFlaskに通知します(app.py この場合)を使用して FLASK_APP 環境変数。 次に、 FLASK_ENV 環境変数から development アプリケーションを開発モードで実行し、デバッガーにアクセスします。 Flaskデバッガーの詳細については、Flaskアプリケーションでエラーを処理する方法を参照してください。 これを行うには、次のコマンドを使用します。

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

必ず設定してください DB_USERNAMEDB_PASSWORD まだ行っていない場合は、環境変数:

  1. export DB_USERNAME="sammy"
  2. export DB_PASSWORD="password"

次に、アプリケーションを実行します。

  1. flask run

開発サーバーが実行されている状態で、ブラウザーを使用して次のURLにアクセスします。

http://127.0.0.1:5000/

最初の開始時にデータベースに追加した本が表示されます。

データベース内の書籍をインデックスページに表示しました。 ここで、ユーザーが新しい本を追加できるようにする必要があります。 次のステップで、本を追加するための新しいルートを追加します。

ステップ5—新しい本を追加する

このステップでは、データベースに新しい本やレビューを追加するための新しいルートを作成します。

ユーザーが本のタイトル、本の著者、ページ数、書評を入力するWebフォームを含むページを追加します。

開発サーバーを実行したままにして、新しいターミナルウィンドウを開きます。

まず、 app.py ファイル:

  1. 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リクエストのみが許可されます。 ユーザーが最初にリクエストしたとき /create GETリクエストを使用してルーティングします。 create.html レンダリングされます。 後でこのルートを編集して、ユーザーが新しい本を追加するためのWebフォームに入力して送信するときのPOSTリクエストを処理します。

新しいを開く create.html テンプレート:

  1. 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 %}

ファイルを保存して閉じます。

基本テンプレートを拡張し、見出しをタイトルとして設定し、 <form> 属性を持つタグ method に設定 post フォームがPOSTリクエストを送信することを示します。

名前の付いたテキストフィールドがあります title、のタイトルデータにアクセスするために使用します /create ルート。

著者用のテキストフィールド、ページ数用の番号フィールド、および書評用のテキスト領域があります。

最後に、フォームの最後に送信ボタンがあります。

これで、開発サーバーが実行されている状態で、ブラウザーを使用してに移動します。 /create ルート:

http://127.0.0.1:5000/create

新しい本を追加ページが表示されます。このページには、本のタイトル、著者、ページ数の入力フィールド、本のレビュー用のテキスト領域、および送信ボタン。

フォームに入力して送信し、サーバーにPOSTリクエストを送信すると、POSTリクエストを処理しなかったため、何も起こりません。 /create ルート。

開ける app.py ユーザーが送信するPOSTリクエストを処理するには:

  1. 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')

ファイルを保存して閉じます。

POSTリクエストは内部で処理します if request.method == 'POST' 調子。 タイトル、作成者、ページ数、およびユーザーが送信したレビューを request.form 物体。

を使用してデータベースを開きます get_db_connection() 関数、およびカーソルを作成します。 次に、を実行します INSERT INTO タイトル、作成者、ページ数を挿入し、に送信されたユーザーを確認するSQLステートメント books テーブル。

トランザクションをコミットし、カーソルと接続を閉じます。

最後に、ユーザーをインデックスページにリダイレクトします。このページでは、既存の本の下に新しく追加された本が表示されます。

開発サーバーが実行されている状態で、ブラウザを使用してに移動します /create ルート:

http://127.0.0.1:5000/create

フォームにデータを入力して送信します。

新しい書評が表示されるインデックスページにリダイレクトされます。

次に、ナビゲーションバーの[作成]ページへのリンクを追加します。 開ける base.html:

  1. 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シリーズの他のチュートリアルをご覧ください。