スポンサーリンク

【Flask】「Docker」上に「 Flask + PostgreSQL 」環境を構築し、データベースに接続してページ表示を行うまでの流れをご紹介。〜 Dockerfile使用 〜

Flask
スポンサーリンク

今回の記事では、Docker環境上でFlask + PostgreSQLの環境を構築し、ポート接続を行いデータベースにFlaskプロジェクトを接続させるまでの流れをご紹介します。DockerfileとDockerーcomposeのymlファイルを使用してコンテナを立ち上げていきまうす。ではコンテナを起動しつつコードのご紹介をおこなっていきます。

スポンサーリンク

Docker上に「Flask + PostgreSQL」環境を構築

まずは下記のプロジェクト構成を準備してください。

.
└── flask
    ├── app
    └── dev
        ├── Dockerfile
        ├── docker-compose.yml
        └── init_db
            └── init.sql

ではコンテナ立ち上げ用のDockerfileにFlaskの記述を書いていきます。また、PostgreSQLはDockerfileは作らずdocker-composeのみで記述していきます。

From python:3

RUN pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org flask

# psycopg2(PostgreSQLクライアント)のインストール
RUN pip install psycopg2

こちらが今回の取得するイメーずです。pastgresSQLに接続後にはPythonクライアントの「psycopg2」をインストール しています。

Flaskデータ保存ページ表示

コンテナに入っての作業になります。まずは下記でコンテナIDを接続し、そのコンテナ入りまょう。

docker ps
[起動中のコンテナが表示]現在二つのコンテナが起動しています。
FlaskとPostgreSQLです。Flaskの方に入ります。
docker exec -it [コンテナID] /bin/bash

#

次にhtmlなどの表示を行うために表示を整えます。今回の記事は下記サイトを参考にしております。下記サイトのDocker-compose.ymlファイルはマウント位置が微妙に間違っているようなのでこちらのサイトの上記ファイルを参考にする以外は基本的に内容は同じになっております。

下記コマンドで構成はできます。

cd usr/local/src/work
mkdir static/css static/js templates
touch app.py static/css/style.css static/js/script.js templates/_layout.html templates/hello.html

コンテナ起動時にマウントしているのでファイル作成はローカルにも反映されますし、ローカルにフォルダを増やしてもコンテナ上に羽根位されるようになっています。私はコマンド上の操作の方がもはや早いのでコマンドで処理。ファイル作成もvim行うようになってしまった。VScodeも好きですが笑。

下記ファイル内に記述を行ってください。

from flask import Flask, render_template, request, jsonify
import psycopg2

app = Flask(__name__)

def getDbConnection():
    return psycopg2.connect("postgresql://test:test@db:5432/test")
    #"postgresql://[設定したID]:[設定したPS]@[設定したID]:5432/[設定したID]"

def getInputs(con):
    inputs = []
    with con.cursor() as cur:
        cur.execute("SELECT * FROM INPUTS")
        for row in cur:
            inputs.append("[" + str(row[1]) + "]" + row[0])
    return inputs
def insertInput(con, value):
    with con.cursor() as cur:
        cur.execute("INSERT INTO INPUTS (value, input_date) VALUES (%s,current_date)", (value, ))

@app.route("/")
def index():
    return "Hello world!"

@app.route("/hello")
def hello():
    with getDbConnection() as con:
        return render_template("hello.html", title = "Helloページ", inputs = getInputs(con))

@app.route("/hello", methods=["POST"])
def hello_post():
    name = request.form["name"]
    message = request.form["message"]
    inputValue = name + ":" + message
    with getDbConnection() as con:
        insertInput(con, inputValue)
        return render_template("hello.html", title = "Hello(post)ページ", input1 = "入力値=[" + inputValue + "]", inputs = getInputs(con))

@app.route("/api/hello/post", methods=["POST"])
def hello_post_ajax():
    name = request.json["name"]
    message = request.json["message"]
    inputValue = name + ":" + message
    with getDbConnection() as con:
        insertInput(con, inputValue)
    return jsonify({"input1": "入力値=[" + inputValue + "]", "input": inputValue})

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0")
<!DOCTYPE html>
<html>
    <head>
        <title>{{title}}</title>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.1.min.js"></script>
        <script src="/static/js/script.js"></script>
        <link rel="stylesheet"
          href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
          crossorigin="anonymous">
        <link rel="stylesheet" href="/static/css/style.css">
    </head>
    <body>
        <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
          <a class="navbar-brand" href="#">Navbar</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarsExampleDefault">
            <ul class="navbar-nav mr-auto">
              <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Link</a>
               </li>
              <li class="nav-item">
                <a class="nav-link disabled" href="#">Disabled</a>
              </li>
              <li class="nav-item dropdown">
                <a class="nav-link dropdown-toggle" href="http://example.com" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
                <div class="dropdown-menu" aria-labelledby="dropdown01">
                  <a class="dropdown-item" href="#">Action</a>
                  <a class="dropdown-item" href="#">Another action</a>
                  <a class="dropdown-item" href="#">Something else here</a>
                </div>
              </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
              <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
              <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>
          </div>
        </nav>
        <main class="main">
          {% block content %}
          {% endblock %}
        </main>
    </body>
</html>
{% extends '_layout.html' %}
{% block content %}
    <div class="jumbotron">
        <div class="container">
            <h1 class="display-3">Hello, world!</h1>
            <p>This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
            <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>
        </div>
    </div>
    <div class="container">
        <form method="POST" action="/hello">
            <div class="form-group">
                <label for="name">名前</label>
                <input type="text" class="form-control" id="name" name="name">
            </div>
            <div class="form-group">
                <label for="message">メッセージ</label>
                <input type="text" class="form-control" id="message" name="message">
            </div>
            <button class="btn btn-lg btn-primary btn-block" type="submit">送信</button>
            <button class="btn btn-lg btn-danger btn-block" type="submit" id="btnSendAjax">非同期送信</button>
        </form>
        <span id="lblInput1" class="hogelabel">{{input1}}</span>
        <ul id="listInputs">
            {% for value in inputs %}
            <li>{{value}}</p>
            {% endfor %}
        </ul>
    </div>
{% endblock %}
body {
    background-color: antiquewhite;
}
$(function() {
    $('#btnSendAjax').click(function () {
        // 入力値取得
        var name = $('input[name=name]').val();
        var message = $('input[name=message]').val();
        $.ajax({
            url: "/api/hello/post",
            type: "POST",
            data: JSON.stringify({name: name, message: message}),
            dataType: "json",
            contentType: "application/json",
            success: function (XMLHttpRequest, textStatus, errorThrown) {
                if (textStatus == 'success' || textStatus == 'nocontent') {
                    // 成功時
                    $('#lblInput1').text(XMLHttpRequest.input1);
                    $('#listInputs').append($("<li>").text(input));
                } else {
                    // エラー時
                    console.error(XMLHttpRequest.responseJSON.Message);
                }
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                // エラー時
                console.error(XMLHttpRequest.responseJSON.Message);
            },
        });
        return false;
    });
});

これで下記を実行すれば表示されるはずです。

flask run -h 0.0.0.0

ホストのブラウザから localhost:5000 にアクセスして「Hello world!」と表示されたら成功です。
http://localhost:5000/helloでサンプルページが表示されて、「送信」ボタン、「非同期送信」ボタンで画面に入力した内容がDBに登録されるはずです。

Flask
スポンサーリンク
tomoをフォローする
スポンサーリンク
SunnyDayTravel-Blog

コメント

  1. […] 【Flask】「Docker」上に「 Flask + PostgreSQL 」環境を構築し、データベースに接… […]

タイトルとURLをコピーしました