0

In python appengine, I have a polymodel class (e.g. Animal). I stored in the datastore some instances of child classes (e.g. Horse).

If I delete the definition of the Horse class in the python source code (or change its name), and get the stored Horse entities using db.get and the entity key, what will happen?

e.g. would the retrieved entity be of type Animal? PolyModel? Would there be an exception?

Uri
  • 25,622
  • 10
  • 45
  • 72
  • Dan's answer is spot on. you can always fetch the underlying entity withouth going through db lib and you may have migrate the entities (fetch, put) to adjust them to reflect your new model. – Tim Hoffman Sep 26 '17 at 10:25

1 Answers1

2

The datastore itself doesn't really know/care about the python class or the data model itself, those are really just implementation details specific to the GAE db or ndb client libraries. You can see that in the Creating an entity example (which uses a generic python client library, without a model definition) - the entity data is simple a dictionary with name-value pairs:

task = datastore.Entity(client.key('Task'))
task.update({
    'category': 'Personal',
    'done': False,
    'priority': 4,
    'description': 'Learn Cloud Datastore'
})

Renaming/deleting the entity model in your application won't delete the entities in the datastore, you'll still be able to see them in the datastore browser.

The key of an already created entity has the entity kind (as a string) embedded in it. Attempting to perform a db.get() on that saved key will raise an KindError exception because it performs a check on the data returned from the datastore against the imported models:

Traceback (most recent call last):
  File "/usr/local/google_appengine/google/appengine/tools/devappserver2/python/request_handler.py", line 226, in handle_interactive_request
    exec(compiled_code, self._command_globals)
  File "<string>", line 12, in <module>
  File "/usr/local/google_appengine/google/appengine/ext/db/__init__.py", line 1540, in get
    return get_async(keys, **kwargs).get_result()
  File "/usr/local/google_appengine/google/appengine/api/apiproxy_stub_map.py", line 613, in get_result
    return self.__get_result_hook(self)
  File "/usr/local/google_appengine/google/appengine/datastore/datastore_rpc.py", line 1715, in __get_hook
    entities = extra_hook(entities)
  File "/usr/local/google_appengine/google/appengine/api/datastore.py", line 643, in local_extra_hook
    return extra_hook(result)
  File "/usr/local/google_appengine/google/appengine/ext/db/__init__.py", line 1509, in extra_hook
    cls1 = class_for_kind(entity.kind())
  File "/usr/local/google_appengine/google/appengine/ext/db/__init__.py", line 299, in class_for_kind
    raise KindError('No implementation for kind \'%s\'' % kind)
KindError: No implementation for kind 'Horse'

So if you want to perform a rework of your models and re-use the already stored data you should keep the old models around to be able to read the data and write it back under the new models.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • What happens if I have an inheritance chain A->B->C and I save C in datastore, and then change the code to be A->C. Would that raise an exception? (because I'm seeing the datastore is aware of the complete inheritance chain) – Uri Sep 22 '17 at 15:27
  • If the inheritance change effectively translates into entity model changes the answer applies. If it also changes the datastore entity ancestry path, then you'd have to also re-write those entities - the ancestry can't be changed once the entities are saved, it's embedded in the entity keys. If the inheritance change doesn't affect neither the models or the entity ancestry it should be transparent (assuming you're still able to get the keys). Don't confuse python class inheritance with the datastore entity ancestry. – Dan Cornilescu Sep 22 '17 at 16:52