2011年3月10日木曜日

Google App Engine データ削除とDatastore Admin について①

認証関係を調査している途中なのだが、Datastore で起きた問題とその解決方法について書いていく。

Datastoreにデータを格納するモデルを作成してテストしていると、データモデルの動作がおかしくなることがある。この場合、AppEngine 管理画面の Datastore Viewer で、データ確認及び削除が可能だ。



しかし異常データによっては、Datastore Viewer がエラーで開くことができないことがある。例えば、おかしなデータがあるKind を選択すると下の画面になる。

Error (500)


仕方ないのでプログラムを作成してデータ削除を試みる。
# -*- coding: utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app
  
class DeleteEntities(webapp.RequestHandler):
    def display(self, finished, counter, total):
        wait = 10
        self.response.headers['Content-Type'] = 'text/html'
        write = self.response.out.write
        write(      '<html>'
                    '<head>' )
        if not finished:
            url = self.request.url.split('?')[0]
            write(  '<meta http-equiv="refresh" content="%d;url=%s?total=%d">' % (wait, url, total))
        write(      '</head>'
                    '<body>')
        if not finished:
            write(  '%d deteted / total %d deleted <br><br>' % (counter,total))
            write(  'Wait %d seconds.' % wait)
        else:
            write(  'total %d deleted <br><br>' % total)
            write(  'Finished.')
        write(      '</body>'
                    '</html>' )
         
    def get(self) :
        limit = 10
        q = db.GqlQuery("SELECT * FROM UserData")
        results = q.fetch(limit)
        counter = len(results) 
        total = self.request.get_range("total") + counter
        db.delete(results)
         
        if counter == limit:
            self.display(False, counter, total)
        else:
            self.display(True, counter, total)
  
def main(): 
    application = webapp.WSGIApplication(
    [ ('/admin/DeleteEntities', DeleteEntities) ], debug=True)
    run_wsgi_app(application)
  
if __name__ == "__main__": 
    main()
29行目の db.GqlQuery のパラメーターを変えれば他の Kind にも対応可能だ。

次のサイト記事を参考に、上記の削除プログラムを作成した(ありがとうございます)。

参考 : Object Design Blog - Google App Engine データストア上のデータをまとめて消す方法


しかし残念ながら、Datastore Viewer でエラーが出ていたKindに対してプログラムを実行すると、次のエラーが出力される。
File "/base/python_runtime/python_lib/versions/1/google/appengine/ext/db/__init__.py", line 1833, in fetch
raw = raw_query.Get(limit, offset, config=config)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py", line 1352, in Get
batch = batcher.next_batch(limit)
File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_query.py", line 1105, in next_batch
batch = self.__next_batch.get_result()
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 534, in get_result
return self.__get_result_hook(self)
File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_query.py", line 1028, in __query_result_hook
for result in query_result.result_list()]
File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 110, in pb_to_query_result
return self.pb_to_entity(pb)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py", line 205, in pb_to_entity
return Entity._FromPb(pb)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py", line 844, in _FromPb
value = datastore_types.FromPropertyPb(prop)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore_types.py", line 1628, in FromPropertyPb
federated_identity=federated_identity)
File "/base/python_runtime/python_lib/versions/1/google/appengine/api/users.py", line 106, in __init__
raise UserNotFoundError
クエリーやGQLの削除は、削除動作前にデータを読み出している。このため、バリデーションが原因で削除できないという問題が発生しているようだ。

では問題のデータはどうやって削除できるのか・・・・・・?。

管理コンソールにある DatastoreAdmin というツールで Kind まるごと削除できるらしい。



記事が長くなったので 次回 に続きます。