Python での Cloud SQL の使用

Python Bookshelf チュートリアルのこのパートでは、サンプルアプリが永続データを Google Cloud SQL に保存する方法について説明します。

このページは複数ページからなるチュートリアルの一部です。最初からの説明や設定手順を確認するには、Python Bookshelf アプリに移動してください。

Cloud SQL インスタンスとデータベースの作成

デプロイされたアプリは、App Engine 環境に組み込まれている Cloud SQL Proxy を使用して Cloud SQL インスタンスと通信します。ただし、アプリをローカルでテストするには、Cloud SQL Proxy のローカルコピーを開発環境にインストールして使用する必要があります。

Cloud SQL Proxy の詳細については、こちらをご覧ください。

Cloud SQL インスタンスに対する基本的な管理タスクは、MySQL クライアントを使用して行うことができます。

Cloud SQL プロキシをインストールする

Cloud SQL Proxy をダウンロードしてインストールします。Cloud SQL Proxy を使用すると、ローカル実行時に Cloud SQL インスタンスに接続できます。

Linux 64 ビット

  1. プロキシをダウンロードします。
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
    
  2. プロキシを実行できるようにします。
    chmod +x cloud_sql_proxy
    

Linux 32 ビット

  1. プロキシをダウンロードします。
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
    
  2. プロキシを実行できるようにします。
    chmod +x cloud_sql_proxy
    

macOS 64 ビット

  1. プロキシをダウンロードします。
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
    
  2. プロキシを実行できるようにします。
    chmod +x cloud_sql_proxy
    

macOS 32 ビット

  1. プロキシをダウンロードします。
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
    
  2. プロキシを実行できるようにします。
    chmod +x cloud_sql_proxy
    

Windows 64 ビット

https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe を右クリックして [名前を付けてリンク先を保存] を選択し、ファイル名を cloud_sql_proxy.exe に変更してプロキシをダウンロードします。

Windows 32 ビット

https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe を右クリックして [名前を付けてリンク先を保存] を選択し、ファイル名を cloud_sql_proxy.exe に変更してプロキシをダウンロードします。
お使いのオペレーティング システムがここに含まれていない場合は、プロキシをソースからコンパイルすることもできます。

Cloud SQL インスタンスを作成する

  1. Cloud SQL for MySQL 第 2 世代のインスタンスを作成します。インスタンスに library などの名前を付けます。インスタンスを使用できるようになるまで数分かかることがあります。準備が完了したら、インスタンスがインスタンス リストに表示されます。
  2. 次に、Cloud SDK を使用して次のコマンドを実行します。[YOUR_INSTANCE_NAME] は、Cloud SQL インスタンスの名前を表します。次のステップで使用するために、connectionName に示された値をメモしておきます。
    gcloud sql instances describe [YOUR_INSTANCE_NAME]

    connectionName の値は、[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME] の形式になります。

Cloud SQL インスタンスを初期化する

  1. 前のステップでメモした connectionName の値を使用して、Cloud SQL Proxy を開始します。

    Linux / macOS

    ./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306

    Windows

    cloud_sql_proxy.exe -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306

    [YOUR_INSTANCE_CONNECTION_NAME] は、前のステップでメモした connectionName の値に置き換えます。

    ローカルでテストを行うため、このステップでローカル コンピュータから Cloud SQL インスタンスへの接続を確立します。ローカルでのアプリのテストが終了するまで、Cloud SQL Proxy を実行したままにしてください。

  2. 次に、新しい Cloud SQL ユーザーとデータベースを作成します。

    Console

    1. Cloud SQL インスタンス library 用に GCP Console を使用して新しいデータベースを作成します。たとえば、bookshelf という名前を使用します。
    2. Cloud SQL インスタンス library 用に GCP Console を使用して新しいユーザーを作成します。

    MySQL クライアント

    1. 別のコマンドライン タブで、MySQL クライアントまたは同様のプログラムを使用してインスタンスに接続します。プロンプトが表示されたら、構成したルート パスワードを使用します。
      mysql --host 127.0.0.1 --user root --password
      
    2. 次のコマンドを使用して、必要なデータベース、ユーザー、アクセス権限を Cloud SQL データベース内に作成します。[MYSQL_USER][MYSQL_PASSWORD] を、使用するユーザー名とパスワードで置き換えてください。
      CREATE DATABASE bookshelf;
      CREATE USER '[MYSQL_USER]' IDENTIFIED BY '[MYSQL_PASSWORD]';
      GRANT ALL ON . TO '[MYSQL_USER]';
      

設定を構成する

ここでは、2-structured-data ディレクトリにあるコードを使用します。ファイルを編集し、このディレクトリでコマンドを実行します。

  1. config.py を編集用に開きます。
  2. PROJECT_ID の値を、GCP Console に表示されるプロジェクト ID に設定します。
  3. DATA_BACKEND の値を cloudsql に設定します。
  4. CLOUDSQL_USERCLOUDSQL_PASSWORDCLOUDSQL_DATABASE の値を、Cloud SQL インスタンスを構成するときに使用した値に設定します。単純にするため、インスタンスを作成するときに設定したルートユーザーとルート パスワードを使用できます。
  5. CLOUDSQL_CONNECTION_NAME の値を、Cloud SQL インスタンスの接続名に設定します。これは、Google Cloud Platform Console 内の Cloud SQL インスタンスの詳細で確認できます。project:region:cloudsql-instance の形式で設定してください。
  6. config.py を保存して閉じます。

デプロイ前に app.yaml で追加の構成を行う必要があります。

  1. app.yaml を編集用に開きます。
  2. cloud_sql_instances の値を、config.py CLOUDSQL_CONNECTION_NAME で使用したものと同じ値に設定します。 project:region:cloudsql-instance の形式で設定してください。この行全体のコメントを解除します。
  3. app.yaml を保存して閉じます。

依存関係のインストール

以下のコマンドを入力して仮想環境を作成し、依存関係をインストールします。

Linux / macOS

virtualenv -p python3 env
source env/bin/activate
pip install -r requirements.txt

Windows

virtualenv -p python3 env
env\scripts\activate
pip install -r requirements.txt

データベース テーブルの作成

アプリケーションは、本棚データを格納するために使用するデータベース テーブルを作成する必要があります。次のコマンドは Cloud SQL インスタンスに接続し、必要なすべてのテーブルを作成します。

Linux / macOS

python bookshelf/model_cloudsql.py

Windows

python bookshelf\model_cloudsql.py

ローカルマシンでのアプリの実行

  1. ローカル ウェブサーバーを起動します。

    python main.py
    
  2. ウェブブラウザに次のアドレスを入力します。

    http://localhost:8080

これで、アプリのウェブページを閲覧し、書籍の追加、編集、削除ができます。

Ctrl+C キーを押してワーカーを終了し、次にローカル ウェブサーバーを終了します。

App Engine フレキシブル環境へのアプリのデプロイ

  1. サンプルアプリをデプロイします。

    gcloud app deploy
    
  2. ウェブブラウザで、次のアドレスを入力します。[YOUR_PROJECT_ID] は実際のプロジェクト ID で置き換えます。

    https://[YOUR_PROJECT_ID].appspot.com
    

アプリを更新する場合は、最初にデプロイしたときと同じコマンドを使って、更新バージョンをデプロイできます。新たにデプロイすると、アプリの新しいバージョンが作成され、それがデフォルトのバージョンに設定されます。古いバージョンはそのまま残り、関連付けられた VM インスタンスも同様に残ります。すべてのアプリ バージョンと VM インスタンスが課金対象のリソースとなるのでご注意ください。

アプリのデフォルト以外のバージョンを削除することで、コストを削減できます。

アプリのバージョンを削除するには:

  1. GCP Console の [App Engine のバージョン] ページに移動します。

    [バージョン] ページに移動

  2. 削除したい、デフォルト以外のアプリのバージョンの横にあるチェックボックスをクリックします。
  3. ページの上部にある [削除] をクリックし、アプリのバージョンを削除します。

課金対象のリソースをクリーンアップする方法の詳細については、このチュートリアルの最後のステップにあるクリーンアップ セクションをご覧ください。

アプリケーションの構造

Bookshelf アプリのデプロイ プロセスと構造

アプリケーションは、すべての永続データを Cloud SQL に格納します。

コードを理解する

このセクションではアプリケーションのコードとその動作を、順を追って説明します。

フォームを使用してユーザー入力の送信を処理する

追加 / 編集 HTML フォームを使用すると、アプリ内で書籍情報の送信内容を追加、編集できます。

追加 / 編集フォームの画像

HTML フォームは、Python テンプレート エンジンである Jinja2 を使用して作成されます。次の Jinja2 テンプレートは、フォームに Title(タイトル)、Author(著者)、Date Published(発行日)、Description(説明)のテキスト入力フィールドを含むように作られています。

{% extends "base.html" %}

{% block content %}
<h3>{{action}} book</h3>

<form method="POST" enctype="multipart/form-data">

  <div class="form-group">
    <label for="title">Title</label>
    <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="author">Author</label>
    <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="publishedDate">Date Published</label>
    <input type="text" name="publishedDate" id="publishedDate" value="{{book.publishedDate}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="description">Description</label>
    <textarea name="description" id="description" class="form-control">{{book.description}}</textarea>
  </div>

  <button type="submit" class="btn btn-success">Save</button>
</form>

{% endblock %}

フォーム送信を処理する

ユーザーが [Add Book] をクリックすると、crud.add ビューにフォームが表示されます。フォームに入力した後にユーザーが [Save] をクリックすると、同じ add 関数がフォームの HTTP POST アクションを処理し、提供されたデータを model.create 関数に渡して Cloud SQL データベースに送るプロセスを開始します。

@crud.route('/add', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        data = request.form.to_dict(flat=True)

        book = get_model().create(data)

        return redirect(url_for('.view', id=book['id']))

    return render_template("form.html", action="Add", book={})

bookshelf/model_cloudsql.py ファイルには、Cloud SQL データベースに保存されたデータの CRUD 関数を実行するコードが含まれています。SQL は、SQLAlchemy と呼ばれるオブジェクト関係マッピング(ORM)を使用して作成されます。ORM では、データモデルを Python オブジェクトとして操作し、同等の SQL を自動的に生成することができます。使用する可能性があるもう 1 つの一般的な ORM は Django ORM です。

Flask との統合を単純にするために、Flask の拡張機能 Flask-SQLAlchemy を使用します。

たとえば、前述のコードの create ステートメントは model_cloudsql.pycreate 関数を呼び出します。これは、Python ディクショナリとして渡された属性を Book コンストラクタ用のキーワード引数に変換することでデータモデルを更新します。その後、モデルをデータベース セッションに追加し、セッションを commit します。SQLAlchemy はこれを SQL INSERT オペレーションに変換し、新しい書籍のエントリをデータベース内に作成します。

def create(data):
    book = Book(**data)
    db.session.add(book)
    db.session.commit()
    return from_sql(book)

登録された書籍の情報をユーザーが編集すると、model_cloudsql.py 内の update 関数が呼び出されます。この関数は、id フィールドで既存のエントリに対するクエリを実行します。次に、更新されたフィールドを反復処理し、既存のモデル内で編集します。最後に、この関数はセッションを commit します。この例では、SQLAlchemy が編集を SQL UPDATE オペレーションとしてモデルに変換します。

def update(data, id):
    book = Book.query.get(id)
    for k, v in data.items():
        setattr(book, k, v)
    db.session.commit()
    return from_sql(book)

ユーザーが書籍を追加した後に [Books] リンクをクリックすると、Cloud SQL データベースに現在保存されているすべての書籍が一覧表示された /books ページに移動します。list 関数は、Cloud SQL データベースから取得したデータを使用して、すべての書籍を一覧表示します。

def list(limit=10, cursor=None):
    cursor = int(cursor) if cursor else 0
    query = (Book.query
             .order_by(Book.title)
             .limit(limit)
             .offset(cursor))
    books = builtin_list(map(from_sql, query.all()))
    next_page = cursor + limit if len(books) == limit else None
    return (books, next_page)

ここで、Python オブジェクト メソッドが適切な SQL にどのように変換されるかを見ることができます。上記のコードで、limit メソッドはデータベースから返すレコードの数を指定します。これにより、クエリによって生成される SELECT SQL ステートメントに LIMIT 句が追加されます。offset メソッドは SELECT ステートメントに OFFSET 句を追加します。これにより、ページ分割を処理するための開始場所を指定し、cursor の値に基づいて追加のページを要求できます。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...