Help us understand the problem. What is going on with this article?

DynamoDBの高レベルクライアント「PynamoDB」が良かった

More than 1 year has passed since last update.

Pythonを使ったDynamoDBの操作には、公式SDKのBoto3を使うことが多いかと思います。Boto3で提供されているのは低レベルなクライアントなため、柔軟な操作ができるという利点はありますが、単純な操作でも記述が複雑になりがちで独自ラッパークラスを作っちゃう問題がありました。

最近PynamoDBという高レベルなクライアントライブラリを見つけて、使ってみたら最高にいい感じだったので基本的な使い方をまとめます。

環境

  • macOS 10.12.6
  • python 3.6.1
  • pynamodb 3.2.1

参考

PynamoDBのドキュメントとServerless FrameworkのExampleに「aws-python-rest-api-with-pynamodb」というのがあったのでそれらを参考にしています。

インストール

$ pip install pynamodb

テーブルモデル定義

まずテーブル定義をします。こんな感じでDjangoのDBモデルっぽく書けます。

todo_model.py
from datetime import datetime

from pynamodb.attributes import UnicodeAttribute, BooleanAttribute, UTCDateTimeAttribute
from pynamodb.models import Model


class ToDoModel(Model):
    class Meta:
        table_name = 'todo_table'
        region = 'ap-northeast-1'
        write_capacity_units = 1
        read_capacity_units = 1

    # テーブル定義
    createdBy = UnicodeAttribute(hash_key=True, null=False)
    createdAt = UTCDateTimeAttribute(range_key=True, null=False, default=datetime.now())
    text = UnicodeAttribute(null=False)
    checked = BooleanAttribute(null=False, default=False)
    updatedAt = UTCDateTimeAttribute(null=False, default=datetime.now())

Metaクラスにテーブルのリソース定義をします。
localstackなどでローカルに起動したDynamoDBに接続する場合はhost = 'http://localhost:8000'と書いておくと指定したホスト・ポートで起動しているDynamoDBが使えるようになります。
テーブル定義の部分では型の定義の他に、ハッシュキーやレンジキーを指定したり、デフォルト値をセットしたり、nullを許すかどうかということが定義できます。

テーブル作成

create_table()メソッドでモデルをもとにテーブルの作成ができます。
構成の設定情報がコードに入ってくるとリソース管理しづらくてイケてないので、これは動作確認などお試しで使うテーブルを作成する時ですね。

todo_app.py
from todo_model import ToDoModel

if not ToDoModel.exists():
    ToDoModel.create_table(wait=True)

exists()でテーブルの有無が取得できます。
wait=Trueを指定するとはテーブル作成が完了するのを待ちます。
テーブルのキャパシティを引数に指定してcreate_table()するとモデルで定義したキャパシティ設定を上書きできます。

todo_app.py
if not ToDoModel.exists():
    ToDoModel.create_table(read_capacity_units=2, write_capacity_units=2, wait=True)

テーブル削除

delete_table()でテーブル削除できます。

todo_app.py
ToDoModel.delete_table()

アイテム作成

まずアイテムオブジェクトを作成し、オブジェクトのsave()メソッドでテーブルに書き込みます。

todo_app.py
a_todo = ToDoModel('Taro', text='Buy books.')

a_todo.save()

最初の2つの引数は自動でハッシュキー、レンジキーの順番で認識されます。レンジキーがないテーブルの場合または今回の例のようにレンジキーにデフォルト値に設定している場合は、いれなくてOKです。

実行するとアイテムが作成されています。
スクリーンショット 2018-03-18 19.35.50.png

アイテムのクエリ検索

ハッシュキーでクエリ検索し、for文でアイテムごとに処理を行っています。

todo_app.py
for item in ToDoModel.query('Taro'):
    print("createdBy:{0}, createdAt:{1}".format(item.createdBy, item.createdAt))
# createdBy:Taro, createdAt:2018-03-18 19:35:43.531462+00:00
# createdBy:Taro, createdAt:2018-03-18 19:37:00.568644+00:00
# createdBy:Taro, createdAt:2018-03-18 19:37:50.249173+00:00

レンジキーを合わせたクエリ

todo_app.py
for item in ToDoModel.query('Taro', ToDoModel.createdAt > datetime(2018, 3, 18, 19, 37)):
    print("createdBy:{0}, createdAt:{1}".format(item.createdBy, item.createdAt))
# createdBy:Taro, createdAt:2018-03-18 19:37:00.568644+00:00
# createdBy:Taro, createdAt:2018-03-18 19:37:50.249173+00:00

アンド条件を使ったクエリ

todo_app.py
for item in ToDoModel.query('Taro', (ToDoModel.checked == False) & (ToDoModel.text.contains('book'))):
    ...

キーを指定したアイテムの取得

ToDoModel.get()の引数にハッシュキー(とレンジキー)を指定することでアイテムオブジェクトとして取得できます。

todo_app.py
a_todo = ToDoModel.get('Taro', datetime(2018, 3, 18, 19, 35, 43, 531462))
print(a_todo.text)
# Buy books.

キーあたりのアイテム数取得

todo_app.py
print(ToDoModel.count('Taro'))
# 12

アイテムの更新

update()の引数にactionリストで複数項目の更新ができます。

todo_app.py
a_todo = ToDoModel.get('Taro', datetime(2018, 3, 18, 19, 35, 43, 531462))

a_todo.update(actions=[
    ToDoModel.text.set('Go to the library.')
])

print(a_todo.text)
# Go to the library.

スクリーンショット 2018-03-18 19.46.57.png
更新されています。

アイテムの削除

todo_app.py
a_todo.delete()

条件付き操作

todo_app.py
a_todo.delete(ToDoModel.checked == True) # a_todo の checked が Trueだった場合アイテムを削除

条件の記述方法はドキュメントのCondition Expressionsに記載されています。

まとめ

裏でどんなクエリを送信しているか見えづらいので、実際にプロダクション等で使うときはそこまで気にして使う必要があると思います。
アップデートも活発なようで今後も使っていきたい所存。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした