{"action":"created","issue":{"url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/54","labels_url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/54/labels{/name}","comments_url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/54/comments","events_url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/54/events","html_url":"https://github.com/kvesteri/sqlalchemy-continuum/issues/54","id":32400494,"number":54,"title":"Have version class inherit from parent","user":{"login":"dtheodor","id":1549648,"avatar_url":"https://avatars.githubusercontent.com/u/1549648?v=3","gravatar_id":"","url":"https://api.github.com/users/dtheodor","html_url":"https://github.com/dtheodor","followers_url":"https://api.github.com/users/dtheodor/followers","following_url":"https://api.github.com/users/dtheodor/following{/other_user}","gists_url":"https://api.github.com/users/dtheodor/gists{/gist_id}","starred_url":"https://api.github.com/users/dtheodor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dtheodor/subscriptions","organizations_url":"https://api.github.com/users/dtheodor/orgs","repos_url":"https://api.github.com/users/dtheodor/repos","events_url":"https://api.github.com/users/dtheodor/events{/privacy}","received_events_url":"https://api.github.com/users/dtheodor/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2014-04-28T21:28:42Z","updated_at":"2015-01-16T14:26:37Z","closed_at":null,"body":"Since ORM models that go beyond example material also define behavior (methods), it would be very convenient if the version models can inherit the behavior of the parent models. This is very useful in accessor methods (`@property`, `to_dict()` kind of methods etc.)\r\n\r\nThis already works partially when someone defines behavior on the Base class, since the version models by default inherit from the same Base.\r\n\r\nThere are a couple of ways to achieve this\r\n\r\n- Have version class directly subclass the parent class. Since the model class is loaded with sql alchemy magic (`__mapper__`, instrumented attributes, relations, validators etc.) this cannot be done in a straightforward way. I implemented this on my own using a hack in the `ModelBuilder` that creates an intermediate model like this:\r\n```python\r\nclass Model(Base):\r\n   #...\r\nclass AbstractModel(Model):\r\n  __abstract__ = True #at least this does not create a table and mapper, need more work to get rid of other \"offensive\" attributes\r\nclass ModelVersion(AbstractModel, VersionBase):\r\n  #...\r\n```\r\n\r\n- Split your models in behavior and declarative so that the version class can directly and safely inherit from the behavior one. This requires manual work for every model\r\n```python\r\nclass _ModelBehavior():\r\n  def useful_method(self):\r\n    #...\r\nclass Model(_ModelBehavior, Base):\r\n  __versioned__ = {\"base_classes\": (_ModelBehavior, VersionBase)}\r\n  #..\r\n```\r\n\r\n- Create a VersionBase that uses `__getattr__` to access attributes from the parent\r\n```python\r\nclass VersionBase():\r\n  def __getattr__(self, name):\r\n    return getattr(self.version_parent, name)\r\n```\r\nThis is the most hacky one with low reliability (this example does not work when version_parent is None for example)\r\n\r\nThoughts?"},"comment":{"url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/comments/70260338","html_url":"https://github.com/kvesteri/sqlalchemy-continuum/issues/54#issuecomment-70260338","issue_url":"https://api.github.com/repos/kvesteri/sqlalchemy-continuum/issues/54","id":70260338,"user":{"login":"dtheodor","id":1549648,"avatar_url":"https://avatars.githubusercontent.com/u/1549648?v=3","gravatar_id":"","url":"https://api.github.com/users/dtheodor","html_url":"https://github.com/dtheodor","followers_url":"https://api.github.com/users/dtheodor/followers","following_url":"https://api.github.com/users/dtheodor/following{/other_user}","gists_url":"https://api.github.com/users/dtheodor/gists{/gist_id}","starred_url":"https://api.github.com/users/dtheodor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dtheodor/subscriptions","organizations_url":"https://api.github.com/users/dtheodor/orgs","repos_url":"https://api.github.com/users/dtheodor/repos","events_url":"https://api.github.com/users/dtheodor/events{/privacy}","received_events_url":"https://api.github.com/users/dtheodor/received_events","type":"User","site_admin":false},"created_at":"2015-01-16T14:26:37Z","updated_at":"2015-01-16T14:26:37Z","body":"I think that I overlooked an sql alchemy feature: [concrete table inheritance](http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative/inheritance.html#concrete-table-inheritance)\r\n\r\nIf I am not missing any weird side-effects, this makes it trivial to implement:\r\n```python\r\nclass Model(Base):\r\n  id = Column(Integer)\r\n  def return_2():\r\n    return 2\r\n\r\nclass ModelVersion(Model):\r\n  __mapper_args__ = {'concrete':True}\r\n  id = Column(Integer)\r\n  transaction_id = Column(Integer)\r\n\r\nassert ModelVersion().return_2() == 2\r\n```"}}