Search code examples
pythongoogle-app-enginegoogle-cloud-datastorepolymodel

Deleting a child class of polymodel in python appengine


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?


Solution

  • 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.