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モデルっぽく書けます。
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()
メソッドでモデルをもとにテーブルの作成ができます。
構成の設定情報がコードに入ってくるとリソース管理しづらくてイケてないので、これは動作確認などお試しで使うテーブルを作成する時ですね。
from todo_model import ToDoModel
if not ToDoModel.exists():
ToDoModel.create_table(wait=True)
exists()
でテーブルの有無が取得できます。
wait=True
を指定するとはテーブル作成が完了するのを待ちます。
テーブルのキャパシティを引数に指定してcreate_table()
するとモデルで定義したキャパシティ設定を上書きできます。
if not ToDoModel.exists():
ToDoModel.create_table(read_capacity_units=2, write_capacity_units=2, wait=True)
テーブル削除
delete_table()
でテーブル削除できます。
ToDoModel.delete_table()
アイテム作成
まずアイテムオブジェクトを作成し、オブジェクトのsave()
メソッドでテーブルに書き込みます。
a_todo = ToDoModel('Taro', text='Buy books.')
a_todo.save()
最初の2つの引数は自動でハッシュキー、レンジキーの順番で認識されます。レンジキーがないテーブルの場合または今回の例のようにレンジキーにデフォルト値に設定している場合は、いれなくてOKです。
アイテムのクエリ検索
ハッシュキーでクエリ検索し、for文でアイテムごとに処理を行っています。
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
レンジキーを合わせたクエリ
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
アンド条件を使ったクエリ
for item in ToDoModel.query('Taro', (ToDoModel.checked == False) & (ToDoModel.text.contains('book'))):
...
キーを指定したアイテムの取得
ToDoModel.get()
の引数にハッシュキー(とレンジキー)を指定することでアイテムオブジェクトとして取得できます。
a_todo = ToDoModel.get('Taro', datetime(2018, 3, 18, 19, 35, 43, 531462))
print(a_todo.text)
# Buy books.
キーあたりのアイテム数取得
print(ToDoModel.count('Taro'))
# 12
アイテムの更新
update()
の引数にactionリストで複数項目の更新ができます。
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.
アイテムの削除
a_todo.delete()
条件付き操作
a_todo.delete(ToDoModel.checked == True) # a_todo の checked が Trueだった場合アイテムを削除
条件の記述方法はドキュメントのCondition Expressionsに記載されています。
まとめ
裏でどんなクエリを送信しているか見えづらいので、実際にプロダクション等で使うときはそこまで気にして使う必要があると思います。
アップデートも活発なようで今後も使っていきたい所存。