[Grok-dev] Very simple Object Inheritance and MeGrok.rdb / SqlAlchemy (over MySql) not working the way I want it to work
Hector Blanco
white.lists at gmail.com
Wed Nov 10 13:33:12 EST 2010
Hello everyone!
I am trying implement a very simple inheritance schema with
megrok.rdb, but I haven't been able to get it working (the way I'd
like to, at least).
I have my two classes (ClassA and ClassB which inherits from ClassA).
------------------------ ClassA.py -------------------------
from megrok import rdb
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata
class ClassA(rdb.Model):
rdb.metadata(testMetadata)
rdb.tablename("a_classes")
rdb.tableargs(schema='test2', useexisting=False)
rdb.polymorphic_identity('class_a')
rdb.polymorphic_on(table='test2.a_classes', column='polymorphic_identity')
id = Column("id", Integer, primary_key=True)
myContainerId = Column("my_container_id",
Integer,
ForeignKey("test2.my_containers_table.id")
)
polymorphicIdentity = Column("polymorphic_identity",
String(50),
nullable=False)
def __init__(self):
self.type = None
self.polymorphicIdentity = "class_a"
-----------------------------------------------------------------
------------------------ ClassB.py -------------------------
from megrok import rdb
import random
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy.types import Integer
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.inheritance.ClassA import ClassA
class ClassB(ClassA):
rdb.metadata(testMetadata)
rdb.tablename("b_classes")
rdb.tableargs(schema='test2', useexisting=False)
rdb.inherits(ClassA) #also fails if I use quotes: rdb.inherits("ClassA")
rdb.polymorphic_identity('class_b')
parentClassId = Column("parent_class_id",
Integer,
ForeignKey("test2.a_classes.id"),
primary_key=True
)
randomField = Column("another_field", Integer)
def __init__(self):
super(ClassB, self).__init__()
self.polymorphicIdentity = "class_b"
self.randomField = int(random.random() * 10000) #Very random indeed
-----------------------------------------------------------------
And then, I have created a third class with a list that should store
instances of type ClassA (and its descendants types):
------------------------ MyContainer.py -------------------------
from megrok import rdb
from sqlalchemy import Column
from sqlalchemy.orm import relationship
from sqlalchemy.types import Integer
from sqlalchemy.types import String
from mylibraries.database.tests.Tables import testMetadata
from mylibraries.database.tests.inheritance.ClassA import ClassA
class MyContainer(rdb.Model):
rdb.metadata(testMetadata)
rdb.tablename("my_containers_table")
rdb.tableargs(schema='test2', useexisting=False)
id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
_whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
_whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
children = relationship(
"ClassA", #Fails the same using the class directly: ClassA (no quotes)
uselist=True,
enable_typechecks = True #Why can't it be True?? ;-)
)
def __init__(self):
self._whateverField1 = "Whatever1"
self._whateverField2 = "Whatever2"
self.children = list()
def addChild(self, child):
if isinstance(child, ClassA):
self.children.append(child)
-----------------------------------------------------------------
If I set the relationship up like this (enabling typechecks in the
"children" relationship) I get the following exception:
------------------------
File "/home/ae/mycustom-cms/grokserver/eggs/SQLAlchemy-0.6.4-py2.4.egg/sqlalchemy/orm/dependency.py",
line 242, in _verify_canload
raise exc.FlushError(
FlushError: Attempting to flush an item of type <class
'mylibraries.database.tests.inheritance.ClassB.ClassB'> on collection
'Container.children', which is not the expected type <class
'mylibraries.database.tests.inheritance.ClassA.ClassA'>. Configure
mapper 'Mapper|ClassA|a_classes' to load this subtype polymorphically,
or set enable_typechecks=False to allow subtypes. Mismatched
typeloading may cause bi-directional relationships (backrefs) to not
function properly.
------------------------
If I disable the typechecking, it seems to work fine. But I would like
to be able "Configure mapper 'Mapper|ClassA|a_classes' to load this
subtype polymorphically", as the exception recommends. Does anyone
know what to do? I've been digging a little in the megrok.rdb package
(eggs/megrok.rdb-0.11-py2.4.egg/megrok/rdb/tests/) and I've seen a
file, "polymorphic.py" where the authors seem to test inheritance, but
they don't use relationships (storage in lists or any of that). Maybe
I need to tell megrok something else, but I haven't seen other
directives that could seem related to object inheritance: I've peeked
in eggs/megrok.rdb-0.11-py2.4.egg/megrok/rdb/directive.py and there
doesn't seem to be any other useful directives for this matter.
And as a little detail... why do I have to manually fill the
"discriminator" column (the "a_classes.polymorphic_identity" column)
if I already explicitly the polymorphic identity in the "static" area
of ClassA and ClassB with the rdb.polymorphic_identity() directive? If
I don't manually assign a value to that column in the constructor of
ClassA/ClassB (by doing self.polymorphicIdentity = "class_b"), said
"polymorphic_identity" field is None (null) in the database. Why? If I
understood properly, in ClassA I'm telling the system to use the
"polymorphic_identity" column as discriminator
(rdb.polymorphic_on(table='test2.a_classes',
column='polymorphic_identity') ) and then, in both ClassA and ClassB
I'm saying that rdb.polymorphic_identity('class_a') or 'class_b'. Why
isn't Megrok automatically inserting "class_a" or "class_b" in the
"polymorphic_identity" column?
Any hint will be deeply appreciated. Thank you all in advance.
More information about the Grok-dev
mailing list