[storm] subclassing and foreign keys with respect to properties from parent
Jamu Kakar
jkakar at kakar.ca
Wed Aug 13 22:26:55 BST 2008
Hi,
Olaf Conradi wrote:
> Ok, so instead of using subclassing I'd be better of using separate classes?
That's what we do in Landscape.
> For example, I'm storing credentials for subjects, and each subject
> can either be an agent or a person. (I left out the credential part
> here)
>
> class Subject(Storm):
> __storm_table__ = 'subjects'
> id = Int(primary=True)
> name = Unicode()
> type = Enum(map={'agent': 0, 'person': 1})
> type_id = Int()
>
>
> class Agent(Storm):
> __storm_table__ = 'agents'
> id = Int(primary=True)
> subject_id = Int()
>
> subject = Reference(subject_id, 'Subject.id')
>
>
> class Person(Storm):
> __storm_table__ = 'persons'
> id = Int(primary=True)
> subject_id = Int()
> gender = Enum(map={'Undisclosed': 0, 'Male': 1, 'Female': 2})
> date_of_birth = Date()
>
> subject = Reference(subject_id, 'Subject.id')
>
>
> What would be the best way to add a property to class Subject to get
> the real subject depending on the type?
We use a very similar pattern in Landscape. What you have is almost
the same. We use a registry to accomplish what you want (untested
code follows):
subject_info_type = {}
def register_subject_info_type(type_info, type_class):
existing_info_class = subject_info_types.get(info_type)
if existing_info_class is not None:
raise RuntimeError("%r has the same info_type of %r" %
(info_class, existing_info_class))
subject_info_types[info_type] = info_class
subject_class.info_type = info_type
Somewhere in your application, before any of these things are used
you need to register subjects info classes, being careful to use
stable info type values since they'll be stored in the database:
register_subject_info_type(1, Agent)
register_subject_info_type(2, Person)
Add a constructor and an info property to your Subject class:
class Subject(Storm):
__storm_table__ = "subjects"
id = Int(primary=True)
name = Unicode()
info_type = Int(allow_none=False)
_info = None
def __init__(self, subject_info_type, **kwds):
if subject_info_type not in subject_info_types.values():
raise UnregisteredSubjectError(
"%s is not a registered subject info type."
% (subject_info_type,))
self.info_type = subject_info_type.get_info_type()
self._info = subject_info_type(self, **kwds)
@property
def info(self):
if self._info is not None:
return self._info
assert self.id is not None
type = subject_info_types[self.info_type]
if not hasattr(type, "__storm_table__"):
info = type.__new__(type)
info.subject = self
else:
info = Store.of(self).get(type, self.id)
self._info = info
return info
Note that the check for a __storm_table__ attribute means you can
use in-memory info classes in the same system. Now subjects are
created as follows:
agent = Subject(Agent, name="Max Smart", secret_code=123)
person = Subject(Person, name="Jane Doe", gender="Female")
Hope this helps,
J.
More information about the storm
mailing list