Hello all, I've been reading SQLALchemy docs and examples for quite some time now, and made a functional model of entities that "ressembles" the way OO works in concept - but it may be very early to say that, it's just a simple concept.
The objective is to have: * a main table, that defines available objects; * a fields table, that defines objects and types for those objects; * an instances table, that creates the objects itself and applies hierarchy; and * a values table, which have been pivoted and polymorphic, to store multiple values of instances. Maybe the code can be a little bit self explanatory; my problem will stand below: <code> from sqlalchemy import * from sqlalchemy.schema import * from sqlalchemy.orm import * from sqlalchemy.orm.collections import * from sqlalchemy.ext.declarative import * from sqlalchemy.ext.associationproxy import * from sqlalchemy.orm.util import * metadata = MetaData() mainObjects = Table( 'objects', metadata, Column('id', Integer, Sequence('obj_id_seq'), primary_key=True), Column('name', Unicode(100), nullable = False), ) mainFields = Table( 'fields', metadata, Column('id', Integer, Sequence('fld_id_seq'), primary_key = True), Column('object_id', Integer, ForeignKey('objects.id'), nullable = False), Column('name', Unicode(100), nullable = False), Column('mask', Unicode(100)), Column('task', Integer) ) mainInstances = Table( 'instances', metadata, Column('id', Integer, Sequence('inst_id_seq'), primary_key=True), Column('object_id', Integer, ForeignKey('objects.id'), nullable = False), Column('parent_id', Integer, ForeignKey('instances.id')), Column('name', Unicode(100), nullable = False), ) mainValuesAttributes = Table( 'values', metadata, Column('id', Integer, Sequence('val_id_seq'), primary_key = True), Column('instance_id', Integer, ForeignKey('instances.id'), nullable = False), Column('key', Unicode(64), nullable = False), Column('item_type', Integer, nullable = False), UniqueConstraint('key', 'instance_id', name = 'val_uq') ) mainIntValues = Table( 'values_int', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Integer, default = None) ) mainUnicodeSmallValues = Table( 'values_char_small', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Unicode(60), default = None) ) mainUnicodeNormalValues = Table( 'values_char_normal', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Unicode(255), default = None) ) mainUnicodeBigValues = Table( 'values_char_big', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', UnicodeText, default = None) ) mainBoolValues = Table( 'values_bool', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Boolean, default = None) ) mainDateValues = Table( 'values_date', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Date, default = None) ) mainDateTimeValues = Table( 'values_datetime', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', DateTime, default = None) ) mainFloatValues = Table( 'values_float', metadata, Column('id', Integer, ForeignKey('values.id'), primary_key = True), Column('value', Numeric(10,2), default = None) ) class MainValues(object): _NONE = 0 _INT = 10 _UNICODE_SMALL = 20 _UNICODE_NORMAL = 30 _UNICODE_BIG = 40 _BOOLEAN = 50 _DATE = 60 _DATETIME = 70 _FLOAT = 80 def __new__(cls, key=None, instance=None, value=None): if hasattr(value, '__class__'): if value.__class__.__name__ == 'str': value = unicode(value) if value.__class__.__name__ == 'unicode': if len(value) < 61: cls = MainUnicodeSmallValues elif 61 <= len(value) < 256: cls = MainUnicodeNormalValues else: cls = MainUnicodeBigValues elif value.__class__.__name__ == 'int': cls = MainIntValues elif value.__class__.__name__ == 'bool': cls = MainBoolValues elif value.__class__.__name__ == 'date': cls = MainDateValues elif value.__class__.__name__ == 'datetime': cls = MainDateTimeValues elif value.__class__.__name__ == 'float': cls = MainFloatValues return object.__new__(cls) class OrmObject(object): ''' http://www.sqlalchemy.org/trac/wiki/UsageRecipes/GenericOrmBaseClass ''' def __init__(self, **kwargs): for key in kwargs.keys(): if not key.startswith('_') and key in self.__dict__.keys(): try: setattr(self, key, kw[key]) except AttributeError, TypeError: print ' ** Key "%s" for %s could not be created.' % (key, self.__class__.__name__) def __repr__(self): attrs = [] for key in self.__dict__: if not key.startswith('_'): attrs.append((key, getattr(self, key))) return '<' + self.__class__.__name__ + '(' + ', '.join(x[0] + '=' + repr(x[1]) for x in attrs) + ')>' class MainFields(OrmObject): pass class MainObjects(OrmObject): instances = association_proxy('_instances', 'name') _property_type = MainFields _property_mapping = '_fields' __map = property(lambda self: getattr(self, self._property_mapping)) def add_field(self, name, task=None, mask=None): property = self.__map.get(name, None) if property is None: self.__map[name] = self._property_type(name=name, task=task, mask=mask, object_id=self.id) else: property.value = value def del_field(self, name): del self.__map[name] def has_field(self, name): return name in self.__map def get_all_fields(self): return self.__map.keys() class MainValuesAttributes(OrmObject): value = association_proxy('_value', 'value', creator=MainValues) class MainValuesMixin(MainValues, MainValuesAttributes): def __init__(self, key, instance, value): self.key = key self.instance_id = instance.id self.value = value def __repr__(self): return '<%s %r=%r>' % (self.__class__.__name__, self.key, self.value if len(self.value) < 100 else self.value[:100] + ' ...') class MainInstances(object): def __init__(self, name, object=None): self.name = name if object is not None: self.parent_id = object.id _property_type = MainValuesMixin _property_mapping = '_values' __map = property(lambda self: getattr(self, self._property_mapping)) def __getitem__(self, key): return self.__map[key].value def __setitem__(self, key, value): property = self.__map.get(key, None) if property is None: self.__map[key] = self._property_type(key, self, value) else: property.value = value def __delitem__(self, key): del self.__map[key] def __contains__(self, key): return key in self.__map def keys(self): return self.__map.keys() def values(self): return [prop.value for prop in self.__map.values()] def items(self): return [(key, prop.value) for key, prop in self.__map.items()] def __iter__(self): return iter(self.keys()) def __repr__(self): return '<%s, name="%s", items=%s>' % (self.__class__.__name__, self.name, len(self.__map)) class MainIntValues(MainValuesMixin): pass class MainUnicodeSmallValues(MainValuesMixin): pass class MainUnicodeNormalValues(MainValuesMixin): pass class MainUnicodeBigValues(MainValuesMixin): pass class MainBoolValues(MainValuesMixin): pass class MainDateValues(MainValuesMixin): pass class MainDateTimeValues(MainValuesMixin): pass class MainFloatValues(MainValuesMixin): pass ''' mapping it all together ... ''' mainFields_mapper = mapper( MainFields, mainFields ) mainObjects_mapper = mapper( MainObjects, mainObjects, properties = { '_instances': relationship(MainInstances), '_fields': relationship(MainFields, collection_class=attribute_mapped_collection('name'), cascade="all, delete-orphan", passive_deletes=True) } ) mainInstances_mapper = mapper( MainInstances, mainInstances, properties = { '_values': relationship(MainValuesAttributes, collection_class=attribute_mapped_collection('key'), cascade="all, delete-orphan", passive_deletes=True) } ) mainValuesMapper = mapper( MainValuesAttributes, mainValuesAttributes, polymorphic_on = mainValuesAttributes.c.item_type, polymorphic_identity = MainValues._NONE, with_polymorphic = '*' ) mainIntValues_mapper = mapper(MainIntValues, mainIntValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._INT) mainUnicodeSmallValues_mapper = mapper(MainUnicodeSmallValues, mainUnicodeSmallValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._UNICODE_SMALL) mainUnicodeNormalValues_mapper = mapper(MainUnicodeNormalValues, mainUnicodeNormalValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._UNICODE_NORMAL) mainUnicodeBigValues_mapper = mapper(MainUnicodeBigValues, mainUnicodeBigValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._UNICODE_BIG) mainBoolValues_mapper = mapper(MainBoolValues, mainBoolValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._BOOLEAN) mainDateValues_mapper = mapper(MainDateValues, mainDateValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._DATE) mainDateTimeValues_mapper = mapper(MainDateTimeValues, mainDateTimeValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._DATETIME) mainFloatValues_mapper = mapper(MainFloatValues, mainFloatValues, inherits=MainValuesAttributes, polymorphic_identity=MainValues._FLOAT) if __name__ == '__main__': engine = create_engine('sqlite://') metadata.bind = engine metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() # using it from pdb import set_trace set_trace() </code> Ok, it works fine. The problem is: I didn't want to replicate the "item_type" for every value created under multiple instances (why do so, if you can set it just once?). I was wondering if there's any way to put the polymorphic identities in mainFields, and then gathered from there to create the polymorphism based on a column like item_type to the mainValues table (mainFields -> mainObjects <-- mainInstances <-- mainValues). I know it's a long way, but I think it's a good line of thinking. Also, the "key" attribute in mainValues doesn't need to exists neither (it is set in mainFields). Is this possible? Thanks for your time. Best regards, Richard. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.