Home > Back-end >  AttributeError: 'Key' object has no attribute 'delete'
AttributeError: 'Key' object has no attribute 'delete'

Time:09-17

I am trying to delete batches of entities of a single Kind from my datastore using the defined function findpins below. The parameter limit tells the number of entities from the Kind Pin to delete. In practice, limit will be just below 20000 to make the daily deletes free. I am doing a keys_only query to avoid reading each entity.

But in testing my code I get the following error.

AttributeError: 'Key' object has no attribute 'delete'

Update 0 If, instead of pin.delete(), I use print pin I see two 80 character strings which I assume are 2 Keys. But I don't know how to use the Keys for deletion.

Update 1 If, instead of keys_only=True, I use keys_only=False I accomplish the delete. But then I have encountered a potential charge for a read which is costly. Is that correct?

How can I fix this?

If you see other issues with my strategy, please say so, too.

Update 2 My revised Python code based on @jccampanero's suggestion is promising but so far fails in isinstance because of its arguments Model and Key. First I got the error message NameError: global name 'Model' is not defined. But then when I replaced Model with Pin I get the error NameError: global name 'Key' is not defined and I cannot imagine what to replace Key with. I don't know what I'm doing with these new definitions, and am particularly uncomfortable with the params **kwargs. So I could really use some help here. Am I on the right track?

Python code (editted with 2 new imports, 2 new def's and 1 new delete command) :

import os
import pprint

from google.appengine.ext import db
from google.appengine.api import datastore
from google.appengine.datastore import datastore_rpc
def delete_async(models, **kwargs):
  if isinstance(models, (basestring, Model, Key)):
    models = [models]
  else:
    try:
      models = iter(models)
    except TypeError:
      models = [models]
  keys = [_coerce_to_key(v) for v in models]

  return datastore.DeleteAsync(keys, **kwargs)

def delete(models, **kwargs):
  delete_async(models, **kwargs).get_result()



class Pin(db.Model):
    name = db.StringProperty()


def findpins(limit):
    pin_query = Pin.all(keys_only=True) 
    for pin in pin_query.run(limit=limit):
        # was: pin.delete()
        delete(pin)
findpins(2)

CodePudding user response:

According to the source code of the library, you can use the delete function for that purpose: it accepts the key of the record you want to delete.

Please, consider the following modification in your code (note the use of the aforementioned db.delete function):

import os
import pprint

from google.appengine.ext import db
class Pin(db.Model):
    name = db.StringProperty()

def findpins(limit):
    pin_query = Pin.all(keys_only=True) 
    for pin in pin_query.run(limit=limit):
        db.delete(pin)
findpins(2)

CodePudding user response:

You just have to modify 2 lines of your code and it should work.

if isinstance(models, (basestring, db.Model, db.Key)):
db.delete(pin)

Final Code:

import os
import pprint

from google.appengine.ext import db
from google.appengine.api import datastore
from google.appengine.datastore import datastore_rpc
def delete_async(models, **kwargs):
  if isinstance(models, (basestring, db.Model, db.Key)):
    models = [models]
  else:
    try:
      models = iter(models)
    except TypeError:
      models = [models]
  keys = [_coerce_to_key(v) for v in models]

  return datastore.DeleteAsync(keys, **kwargs)

def delete(models, **kwargs):
  delete_async(models, **kwargs).get_result()



class Pin(db.Model):
    name = db.StringProperty()


def findpins(limit):
    pin_query = Pin.all(keys_only=True) 
    for pin in pin_query.run(limit=limit):
        # was: pin.delete()
        db.delete(pin)
findpins(2)
  • Related