从Python中删除后,仍然可以在数据存储区查看器中看到GAE NBD实体并刷新Memchach

时间:2016-10-20 11:41:07

标签: python google-app-engine google-cloud-datastore app-engine-ndb

下面是一个最小Python示例,显示实体添加到NDB,然后删除所有实体。

然而,尽管实体似乎已被删除,但Datastore Viewer仍会显示它们 - 即使在我刷新Memcache.

之后

我应该更改哪些内容以便删除NDB实体?

我的代码:

from google.appengine.ext import ndb
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

from models import Data

KEY = "fastsimon"
datum_key = dict()

class InvalidHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Invalid entry')

class GetHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Get!\n')
        name = self.request.get('name')
        out_str = "Should not be seen"
        try:
            ancestor_key = datum_key[name]
            qry = Data.owner_query(ancestor_key)
            data = qry.fetch()
            out_str = data[-1].value
        except KeyError:
            out_str = "None"
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write(out_str)

class EndHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('End!')
        qry = Data.query().iter(keys_only=True)
        print "before delete"
        list_of_keys = list()
        for q in qry:
            print "ndb.Key('Datum',q):",ndb.Key('Datum',q.integer_id())
            list_of_keys.append(ndb.Key('Datum',q.integer_id()))
        print "list_of_keys:",list_of_keys
        ndb.delete_multi(list_of_keys)
        print "after delete"
        for q in qry:
            print "ndb.Key('Datum',q):",ndb.Key('Datum',q.integer_id())

class SetHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Set!\n')
        name=self.request.get('name')
        data = Data(parent=ndb.Key("Datum", KEY),
                    name=name,
                    value=self.request.get('value'))
        print "data:",data
        ret_key = data.put()
        datum_key[name] = ret_key

def main():
    application = webapp.WSGIApplication([
            ('/get', GetHandler),
            ('/set', SetHandler),
            ('/end', EndHandler)],     
            debug=False) 
    global app
    app = application
    run_wsgi_app(app)

if __name__ == 'main':
    main()

models.py:

from google.appengine.ext import ndb

class Data(ndb.Model):
    name = ndb.StringProperty() # Upto 500 characters
    value = ndb.TextProperty(required=True) # Unlimited length

    @classmethod
    def owner_query(cls, parent_key):
        return cls.query(ancestor=parent_key).order(cls.name)

我采取的步骤:

  1. Cleared Datastore:
  2. Cleared Datastore

    1. 在浏览器中执行以下操作:
    2. http://localhost:8080/set?name=a&value=1
    3. http://localhost:8080/set?name=b&value=2
    4. http://localhost:8080/end
    5. 调试行是:

      data: Data(key=Key('Datum', 'fastsimon', 'Data', None), name=u'a', value=u'1')
      INFO     2016-10-20 11:29:34,213 module.py:788] default: "GET /set?name=a&value=1 HTTP/1.1" 200 5
      data: Data(key=Key('Datum', 'fastsimon', 'Data', None), name=u'b', value=u'2')
      INFO     2016-10-20 11:29:50,442 module.py:788] default: "GET /set?name=b&value=2 HTTP/1.1" 200 5
      before delete
      ndb.Key('Datum',q): Key('Datum', 4661104668049408)
      ndb.Key('Datum',q): Key('Datum', 5787004574892032)
      list_of_keys: [Key('Datum', 4661104668049408), Key('Datum', 5787004574892032)]
      after delete
      INFO     2016-10-20 11:30:04,125 module.py:788] default: "GET /end HTTP/1.1" 200 4
      

      但是,当我转到数据存储区查看器并按下Flush Memcache时,我仍然看到那里的实体:

      when I go to the Datastore viewer and press the Flush Memcache, I still see  entities there

      我应该更改哪些内容以便删除NDB实体?

2 个答案:

答案 0 :(得分:1)

In general you need to be careful with your queries when you use ancestries for your entities - queries with and without ancestor keys specified will produce different (non-overlapping) results. See Ancestor Queries

The root cause of your problem is that the keys you're building in the list_of_keys to be deleted do not match the original keys if the respective entities have ancestors, thus what's passed to ndb.delete_multi may miss some of the keys you intend to delete.

ndb.Key('Datum',q.integer_id()) produces a key for an entity without an ancestor which will not match the q key if q is the key of an entity with an ancestor.

A simple solution would be to not convert the keys you want to delete, instead pass them directly to ndb.delete_multi(), for example you could simply do ndb.delete_multi([key for key in qry]) instead of ndb.delete_multi(list_of_keys)

答案 1 :(得分:1)

根据@DanCornilescu的优秀建议,我更改了EndHandler的代码,它现在删除了像冠军一样的实体。

代码:

from google.appengine.ext import ndb
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

from models import Data

KEY = "fastsimon"
datum_key = dict()

class InvalidHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Invalid entry')

class GetHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Get!\n')
        name = self.request.get('name')
        out_str = "Should not be seen"
        try:
            ancestor_key = datum_key[name]
            qry = Data.owner_query(ancestor_key)
            data = qry.fetch()
            out_str = data[-1].value
        except KeyError:
            out_str = "None"
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write(out_str)


class EndHandler(webapp.RequestHandler):
    def show_entities(self):
        for q in datum_key.values():
            k = ndb.Key('Datum', 'fastsimon', 'Data',q.integer_id())
            print "entity for",k,"=>", ndb.Key('Datum', 'fastsimon', 'Data',q.integer_id()).get()

    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('End!')
        print "datum_key.values():",datum_key.values()
        print "before delete"
        self.show_entities()
        ndb.delete_multi(datum_key.values())
        print "after delete"
        self.show_entities()


class SetHandler(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('Set!\n')
        name=self.request.get('name')
        data = Data(parent=ndb.Key("Datum", KEY),
                    name=name,
                    value=self.request.get('value'))
        ret_key = data.put()
        datum_key[name] = ret_key
        print "data:",data

def main():
    application = webapp.WSGIApplication([
            ('/get', GetHandler),
            ('/set', SetHandler),
            ('/end', EndHandler)],     
            debug=False) 
    global app
    app = application
    run_wsgi_app(app)

if __name__ == 'main':
    main()

调试行:

data: Data(key=Key('Datum', 'fastsimon', 'Data', 4943129400573952), name=u'z', value=u'55')
INFO     2016-10-20 13:40:17,008 module.py:788] default: "GET /set?name=z&value=55 HTTP/1.1" 200 5
data: Data(key=Key('Datum', 'fastsimon', 'Data', 6069029307416576), name=u'x', value=u'88')
INFO     2016-10-20 13:40:28,556 module.py:788] default: "GET /set?name=x&value=88 HTTP/1.1" 200 5
datum_key.values(): [Key('Datum', 'fastsimon', 'Data', 4943129400573952), Key('Datum', 'fastsimon', 'Data', 6069029307416576)]
before delete
entity for Key('Datum', 'fastsimon', 'Data', 4943129400573952) => Data(key=Key('Datum', 'fastsimon', 'Data', 4943129400573952), name=u'z', value=u'55')
entity for Key('Datum', 'fastsimon', 'Data', 6069029307416576) => Data(key=Key('Datum', 'fastsimon', 'Data', 6069029307416576), name=u'x', value=u'88')
after delete
entity for Key('Datum', 'fastsimon', 'Data', 4943129400573952) => None
entity for Key('Datum', 'fastsimon', 'Data', 6069029307416576) => None
INFO     2016-10-20 13:40:40,517 module.py:788] default: "GET /end HTTP/1.1" 200 4

并且数据存储区查看器不显示任何实体。