[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