LoginSignup
27
22

More than 5 years have passed since last update.

Python3でDatastore を動かしてみた

Posted at

概要

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という種類のエンティティが登録されます。
スクリーンショット 2019-03-05 20.51.15.png

ちなみに下記の方法でも作成可能です

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を作成してみます。

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サービスを開発してみた

27
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
22