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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.