概要
GAE上でDjango・Pythonを動かしてWebサービスを作るに当たり、GoogleDatastoreを使いました。
この記事ではPython3でGoogleDatastoreを操作する方法をまとめます。
GoogleDatastoreって
詳しくは上記のリンク参照。簡潔に言うと...
- NoSQL
- RESTfulインターフェース
- シームレスかつ自動にスケール
参考
導入
install
ライブラリをpip3でインストールします。
pip3 install google-cloud-datastore
IAM
ローカル環境でDatastoreAPIを叩くには、IAMの設定が必要です。
# サービスアカウントを作成
gcloud iam service-accounts create [NAME]
# 権限付与
gcloud projects add-iam-policy-binding [PROJECT_ID] --member "serviceAccount:[NAME]@[PROJECT_ID].iam.gserviceaccount.com" --role "roles/owner"
# キーファイル作成
#
gcloud iam service-accounts keys create [FILE_NAME].json --iam-account [NAME]@[PROJECT_ID].iam.gserviceaccount.com
# 環境変数の設定: [FILE_NAME].jsonのPATHを指定する
# .bashrcにも書いておきましょう。
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
操作
エンティティの作成
まずはエンティティを作成してみます。
from google.cloud import datastore
# クライアントの設定
client = datastore.Client()
# エンティティ
key = client.key("Task2")
entity = datastore.Entity(key)
entity['description'] = "Buy milk"
entity['username'] = "Qiita"
client.put(entity)
そうすると下記のように、Task2という種類のエンティティが登録されます。
ちなみに下記の方法でも作成可能です
entity = datastore.Entity(key)
entity.update({
"description": "Buy milk",
"username": "Qiita",
})
client.put(entity)
ID指定でエンティティを取得
先ほど作成したエンティティを、ID指定で取得してみます。
id = 5703374003503104
key = client.key("Task2", id)
entity = client.get(key)
print(entity)
# <Entity('Task2', 5703374003503104) {'username': 'Qiita', 'description': 'Buy milk'}>
要素の取得は、entity.get('要素名')
を使うか、entity['要素名']
で取得できます
print(entity.get("username"))
# 'Qiita'
print(entity["username"])
# 'Qiita'
# getの場合、第2引数に要素名を取得できない場合に代入する値を指定可能
entity.get("comment", "No comment")
# 'No comment'
クエリ
クエリのため、テストデータを増やします。
key = client.key("Task2")
# A-san
entityA = datastore.Entity(key)
dataA = dict()
dataA['username']='A-san'
dataA['description']='Help B-san'
entityA.update(dataA)
# B-san
entityB = datastore.Entity(key)
dataB = dict()
dataB['username']='B-san'
dataB['description']='Buy beer'
entityB.update(dataB)
# リスト内のエンティティをDatastoreに保存
client.put_multi([entityA, entityB])
username=Qiitaの条件でクエリを実行してみます。
# kindにエンティティ種類名を指定
query = client.query(kind="Task2")
# filter: 要素名、演算子、値の順に指定
query.add_filter("username", "=", "Qiita")
# fetchで取得。
list(query.fetch())
[<Entity('Task2', 5703374003503104) {'username': 'Qiita', 'description': 'Buy milk'}>]
ソート
query.order
で、ソートを指定可能
query = client.query(kind="Task2")
query.order=["username"]
list(query.fetch())
# [
# <Entity('Task2', 5150370657468416) {'username': 'A-san', 'description': 'Help B-san'}>,
# <Entity('Task2', 5713320610889728) {'username': 'B-san', 'description': 'Clean desk up'}>,
# <Entity('Task2', 5703374003503104) {'username': 'Qiita', 'description': 'Buy milk'}>
# ]
distinct_on
ある要素で、重複を省いて一覧を取得したいときは、query.distinct_on
を使うと良い
# username一覧を取得する
query = client.query(kind="Task2")
query.distinct_on = ['username']
usernames = [
e.get('username') for e in query.fetch()
]
index
Datatoreでは、~~面倒なことに、~~複数要素でフィルターかソートするためにはindexを作る必要がある。
例えば、前準備なしに書きを実行すると。。。
query = client.query(kind="Task2")
query.add_filter("username", "=", "Qiita")
query.order=["description"]
list(query.fetch())
こんなエラーが返ってきます。
google.api_core.exceptions.FailedPrecondition: 400 no matching index found. recommended index is:
- kind: Task2
properties:
- name: username
- name: description
言われたとおり、index.yamlを作成してみます。
indexes:
- kind: Task2
properties:
- name: username
- name: description
下記コマンドを叩いて、index.yamlを登録します。
gcloud datastore indexes create index.yaml
index.yamlで登録したインデックスは即座に反映されないようです。少し時間をおいてから、同じクエリを試してみるとエラーが出ないはずです。
ちなみに
写真から次の旅行先を探すことをコンセプトにしたWebサービス 【Where to Visit?】を作りました。
本サービスはGoogleAppEngine上のDjangoで動いるのですが、データ保存先としてGoogleDatastoreを利用しています。
こっちの記事も読んでみてください。↓
GAE×DjangoでWebサービスを開発してみた