Reputation: 23
I'm using ndb.polymodel.PolyModel
to model different types of social media accounts. After an account has been deleted some cleanup has to be done (depending on the subclass).
I tried implementing a _pre_delete_hook
on the subclass, but it never gets executed. When adding the exact same hook to its parent class it does get executed:
class Account(polymodel.PolyModel):
user = ndb.KeyProperty(kind=User)
@classmethod
def _pre_delete_hook(cls, key):
# Works as expected
pass
class TwitterAccount(Account):
twitter_profile = ndb.StringProperty()
@classmethod
def _pre_delete_hook(cls, key):
# Never gets called
pass
t_account = TwitterAccount.get_by_id(1)
t_account.key.delete()
Seems strange to me as I would expect the subclass hook to override its parent. Or is this expected behavior?
Solution:
I missed the fact that a delete
operation happens on a Key
(not a model instance). The key itself only knows the name of the topmost class (Account
in this case).
I ended up defining a custom _delete_hook
instance method on the subclass. When _pre_delete_hook
gets called, I fetch the entity and then check if its class has a specific delete_hook to execute:
# In subclass:
def _delete_hook(self):
# Do stuff specific for this subclass
return
# In parent class
@classmethod
def _pre_delete_hook(cls, key):
s = key.get()
if hasattr(s, '_delete_hook'):
s._delete_hook()
Upvotes: 0
Views: 336
Reputation: 12986
Unfortunately this is expected though non-obvious behaviour
When you call key
delete with a PolyModel
you are only calling delete on the parent class.
Have a look at the Key you are calling delete on, you will see the Kind is the parent Model. It then looks up the class via the Kind -> class map which will give you an Account
class. Have a read up on how PolyModel works. It stores all Account sub classes as Account and has an extra property that describes the inheritance heirarchy. So that a query on Account will return all Account subclasses, but a query on TwitterAccount will only return that subclass.
Calling ndb.delete_multi won't work either.
If you want a specific PolyModel subclass pre delete hook to run, you will have to add a delete method to the subclass, call that, that can then call the subclass _pre_delete_hook (and may be call super).
But that will cause issues if you ever call key.delete
directly
Upvotes: 0