kkp
kkp

Reputation: 33

NDB - Setting kind name independently of model name

Similar to the question asked here:

Set a kind name independently of the model name (App Engine datastore)

but instead for NDB.

My use case is as follows:

We modified our db code to use prefixes for the datastore kind names (e.g. instead of 'Car' it uses ModuleName_Car). We are now upgrading to NDB and don't have a way to change 'Car' to ModuleName_Car, and subsequently ndb is unable to read existing data. Any workarounds that don't involve naming my model 'ModuleName_Car(ndb.Model)' ?

Upvotes: 3

Views: 416

Answers (3)

max
max

Reputation: 29983

To expand on David's answer

class NdbCredential(ndb.Expando):
    ...
    @classmethod
    def _get_kind(cls):
        return 'Credential'

does the job.

Upvotes: 1

Here's how I approached this problem for the specific use case of mixing db and ndb Models/Keys.

Suppose your db class was defined as:

class CarModel(db.Model):
  brand = db.ReferenceProperty(reference_class=Brand) 

And db.ReferenceProperty Brand identified itself with brand.kind() == "my_Brand". The corresponding ndb.Model might look like:

class CarModel(ndb.Model):
  brand = KeyProperty(kind="my_Brand")

This should solve your issue since myBrand is properly referenced by the kind. In my case, I specifically wanted to mix db.Key into the ndb.Model by assigning the field by the ndb.Key, db.Key, or db.Model and then retrieving a db.Key to be used in query filters and other matching logic. I subclassed ndb.KeyProperty to handle the behavior as follows (code golf/corrections welcome):

class DbReferenceProperty:
  @staticmethod
  def _db_to_ndb_key(entity):
    if entity is None:
      return None
    ndb_key = ndb.Key.from_old_key(entity) if type(entity) == db.Key else ndb.Key.from_old_key(entity.key())

   #Overrides ndb.KeyProperty method
  def _validate(self, value):
    if not isinstance(value, ndb.Key) and not isinstance(value, db.Key) and not isinstance(value, db.Model):
      raise TypeError("Unexpected type: %s" % repr(value))

  #Overrides ndb.KeyProperty method
  def _to_base_type(self, value):
    if isinstance(value, db.Key) or isinstance(value, db.Model):
      value = DbReferenceProperty._db_to_ndb_key(value)
    return value  

  #Overrides ndb.KeyProperty method
  def _from_base_type(self, value):
    prop_id, kind_str = value.id(), value.kind()
    db_key = db.Key.from_path(kind_str, prop_id)
    return db_key

Upvotes: 0

David Pope
David Pope

Reputation: 6587

The NDB Cheat Sheet doc hinted enough (via _get_kind()) to point me to this section of the documentation:

The kind is normally the name of the model class to which the entity belongs ("Account" in the example above), but can be changed to some other string by overriding the classmethod _get_kind().

Upvotes: 4

Related Questions