Flask, Dynamo D B, Lambdaを使用した C R U Dアプリケーションの作成

Flask, DynamoDB, Lambdaを使用したCRUDアプリケーションの作成 #

このチュートリアルでは、Flask、DynamoDB、およびAWS Lambdaを使用して、CRUD(Create, Read, Update, and Delete)機能を持つ簡単なウェブアプリケーションを作成します。これらのテクノロジーを組み合わせることで、スケーラブルで効率的なサーバーレスアーキテクチャを実現できます。

必要な環境 #

  • Python 3.8+
  • AWSアカウント
  • pip
  • Virtualenv (オプション)

ステップ1: プロジェクトのセットアップ #

  1. プロジェクトディレクトリを作成し、移動します。
mkdir flask-dynamodb-crud
cd flask-dynamodb-crud

仮想環境を作成し、アクティベートします。

python -m venv venv
source venv/bin/activate

必要なパッケージをインストールします。

pip install flask boto3 zappa

ステップ2: Flaskアプリケーションの作成 #

  1. プロジェクトディレクトリ内で、app.pyという名前のファイルを作成し、以下のコードを追加します。
from flask import Flask, render_template, request, redirect, url_for
import boto3

app = Flask(__name__)

@app.route('/')
def home():
    return "Hello, Flask DynamoDB CRUD!"

if __name__ == '__main__':
    app.run(debug=True)

アプリケーションを実行して、ローカル環境で動作することを確認します。

python app.py

ステップ3: DynamoDBテーブルの作成 #

AWS管理コンソールにログインし、DynamoDBサービスに移動します。 「テーブルの作成」をクリックし、以下の設定でテーブルを作成します。

  • テーブル名: todos
  • パーティションキー: id (文字列)

テーブルが作成されるのを待ちます。

ステップ4: Boto3を使ったDynamoDBへのアクセス #

app.pyに以下のコードを追加し、DynamoDBに接続します。

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todos')

ステップ5: CRUD機能の実装 #

create機能とread機能をまずは作成します。

from flask import Flask, render_template, request, redirect, url_for
import boto3

app = Flask(__name__)
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todos')

# Home
@app.route('/')
def home():
    #return "Hello, Flask DynamoDB CRUD!"
    response = table.scan()
    items = response['Items']
    return render_template('index.html', items=items)

# Create GET
@app.route('/create', methods=['GET'])
def create_form():
    return render_template('create.html')

# Create POST
@app.route('/create', methods=['POST'])
def create():
    item = {
        'id': request.form['id'],
        'task': request.form['task'],
        'status': request.form['status']
    }
    table.put_item(Item=item)
    return redirect(url_for('home'))

# Read Single
@app.route('/read/<string:id>', methods=['GET'])
def read(id):
    response = table.get_item(Key={'id': id})
    return render_template('read.html', item=response['Item'])

if __name__ == '__main__':
    app.run(debug=True)

必要なライブラリをインポートします。

  • Flask, render_template, request, redirect, url_for: Flaskフレームワークで使用される関数やクラスを提供します。
  • boto3: AWSのサービスとやり取りするためのPythonライブラリです。

Flaskアプリケーションインスタンスを作成し、DynamoDBリソースと’todos’という名前のテーブルを定義します。

  • ホームルート('/'): このルートは、DynamoDBテーブルからすべてのアイテムを取得し、それらをHTMLテンプレート(index.html)に表示します。
  • タスク作成フォームルート('/create'、GETリクエスト): このルートは、タスクを作成するためのHTMLフォーム(create.html)を表示します。
  • タスク作成ルート('/create'、POSTリクエスト): このルートは、フォームから送信されたデータを使用して、新しいタスクをDynamoDBテーブルに追加し、その後、ホームルートにリダイレクトします。
  • タスク詳細表示ルート('/read/string:id'、GETリクエスト): このルートは、指定されたIDを持つタスクをDynamoDBから取得し、その詳細をHTMLテンプレート(read.html)に表示します。

最後に、if __name__ == '__main__': でアプリケーションが直接実行されている場合、デバッグモードでアプリケーションを起動します。

このコードでは、タスクの更新と削除機能が実装されていません。機能を追加することで、完全なCRUDアプリケーションになります。

ステップ6: テンプレートの作成 #

templatesディレクトリを作成し、index.html,create.html,read.htmlを作成します。

[index.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo List</title>
</head>
<body>
    <h1>Todo List</h1>
    <ul>
        {% for item in items %}
            <li>
                <a href="{{ url_for('read', id=item.id) }}">{{ item.task }}</a>
            </li>
        {% endfor %}
    </ul>
    <a href="{{ url_for('create') }}">Create a new Todo</a>
</body>
</html>

[create.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Create Todo</title>
</head>
<body>
    <h1>Create a new Todo</h1>
    <form action="{{ url_for('create') }}" method="post">
        <label for="id">ID:</label>
        <input type="text" name="id" required>
        <label for="task">Task:</label>
        <input type="text" name="task" required>
        <label for="status">Status:</label>
        <select name="status">
            <option value="not started">Not started</option>
            <option value="in progress">In progress</option>
            <option value="completed">Completed</option>
        </select>
        <button type="submit">Create</button>
    </form>
    <a href="{{ url_for('home') }}">Back to Home</a>
</body>
</html>

[read.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo</title>
</head>
<body>
    <h1>{{ item.task }}</h1>
    <p>Status: {{ item.status }}</p>
    <a href="{{ url_for('home') }}">Back to Home</a>
</body>
</html>

ステップ7: Zappaを使ってAWS Lambdaにデプロイ #

Zappaの設定ファイルzappa_settings.jsonを作成します。

{
    "production": {
        "app_function": "app.app",
        "aws_region": "ap-northeast-1",
        "profile_name": "default",
        "project_name": "flask-dynamodb-crud",
        "runtime": "python3.8",
        "s3_bucket": "your-s3-bucket-name"
    }
}

Zappaを使ってデプロイします。

zappa deploy production

デプロイが完了したら、表示されるURLにアクセスしてアプリケーションが正常に動作していることを確認します。

ステップ8: Crudの更新と削除を追加する。 #

テンプレートを作成します。

[update.html]

<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Update Todo</title>
</head>
<body>
    <h1>Update Todo</h1>
    <form action="{{ url_for('update', id=item.id) }}" method="post">
        <input type="hidden" name="_method" value="PUT">
        <label for="task">Task:</label>
        <input type="text" name="task" value="{{ item.task }}" required>
        <label for="status">Status:</label>
        <select name="status">
            <option value="not started" {% if item.status == 'not started' %}selected{% endif %}>Not started</option>
            <option value="in progress" {% if item.status == 'in progress' %}selected{% endif %}>In progress</option>
            <option value="completed" {% if item.status == 'completed' %}selected{% endif %}>Completed</option>
        </select>
        <button type="submit">Update</button>
    </form>
    <a href="{{ url_for('read', id=item.id) }}">Cancel</a>
</body>
</html>

[delete.html]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Delete Todo</title>
</head>
<body>
    <h1>Delete Todo</h1>
    <p>Are you sure you want to delete "{{ item.task }}"?</p>
    <form action="{{ url_for('delete', id=item.id) }}" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <button type="submit">Yes, delete it</button>
    </form>
    <a href="{{ url_for('read', id=item.id) }}">Cancel</a>
</body>
</html>

[app.py]

# Update POST
@app.route('/update/<string:id>', methods=['POST'])
def update(id):
    task = request.form['task']
    status_alias = request.form['status']

    response = table.update_item(
        Key={'id': id},
        UpdateExpression="set task=:t, #status_alias=:s",
        ExpressionAttributeValues={
            ':t': task,
            ':s': status_alias
        },
        ExpressionAttributeNames={
            "#status_alias": "status"
        },
        ReturnValues="UPDATED_NEW"
    )

    return redirect(url_for('read', id=id))

# Delete POST
@app.route('/delete/<string:id>', methods=['POST'])
def delete(id):
    table.delete_item(Key={'id': id})
    return redirect(url_for('home'))

# update GET
@app.route('/update/<string:id>', methods=['GET'])
def update_form(id):
    response = table.get_item(Key={'id': id})
    return render_template('update.html', item=response['Item'])

# delete GET
@app.route('/delete/<string:id>', methods=['GET'])
def delete_form(id):
    response = table.get_item(Key={'id': id})
    return render_template('delete.html', item=response['Item'])

タスク更新ルート('/update/string:id'、POSTリクエスト): このルートは、フォームから送信されたデータを使用して、指定されたIDのタスクをDynamoDBテーブルで更新し、その後、更新されたタスクの詳細ページにリダイレクトします。

  • update_itemメソッドを使用して、DynamoDBテーブルのアイテムを更新します。
  • UpdateExpressionにより、タスクとステータスの属性を更新します。
  • ExpressionAttributeValuesにより、更新される値を設定します。
  • ExpressionAttributeNamesにより、予約語として使用できない属性名(この場合は’status')をエイリアスとして設定します。

タスク削除ルート('/delete/string:id'、POSTリクエスト): このルートは、指定されたIDのタスクをDynamoDBテーブルから削除し、その後、ホームルートにリダイレクトします。

  • delete_itemメソッドを使用して、DynamoDBテーブルからアイテムを削除します。

タスク更新フォームルート('/update/string:id'、GETリクエスト): このルートは、指定されたIDのタスクの情報をもとに、タスクを更新するためのHTMLフォーム(update.html)を表示します。

  • get_itemメソッドを使用して、DynamoDBテーブルからアイテムを取得します。

タスク削除確認フォームルート('/delete/string:id'、GETリクエスト): このルートは、指定されたIDのタスクの情報をもとに、タスクを削除する前に確認を行うHTMLフォーム(delete.html)を表示します。

  • get_itemメソッドを使用して、DynamoDBテーブルからアイテムを取得します。

ステップ9: Zappaで更新する #

Lambda関数を更新します。

$ zappa update production

ステップ10: クリーンアップ #

  • Zappaを使ってアプリケーションを削除します。
$ zappa undeploy production
  • AWS管理コンソールからDynamoDBテーブルtodosを削除します

まとめ #

これで、Flask, DynamoDB, Lambda, Zappaを使ったCRUDアプリケーションの作成とデプロイが完了しました。これをベースにして、アプリケーションをカスタマイズし、さらに多機能なWebアプリケーションを作成することができます。例えば、認証機能を追加してユーザーがログインできるようにする、複数のテーブルやリレーションを持つデータモデルを実装する、フロントエンドフレームワークを利用してUIを向上させるなどが考えられます。

このチュートリアルでは、サーバーレスアーキテクチャを利用して低コストでスケーラブルなWebアプリケーションを作成する方法を学びました。