| hey michael - I committed another small thing to mapper to help some more with this. with a regular mapper->mapper inheritance, the submapper can specify the same table as the parent. I worked up many-to-many relationships on both Test and Test1 (to test that you can stick them on the child objects too) and got a lot going. the get() method needs some help. the example includes a customized get() that does the job, so this is another candidate for a MapperExtension method, i.e. override the "get()". The *next* step when we get this really going, will be a stock MapperExtension that does all this work for you. then this will be a totally supported feature thats pluggable. |
import sys
from sqlalchemy import *
import sqlalchemy.mapping
tests = Table('tests',
Column('id', Integer, primary_key=True),
Column('type', String),
Column('data1', Integer),
Column('data2', String))
foo = Table('foo',
Column('id', Integer, primary_key=True),
Column('data', String(20)))
test_foo = Table('test_foo',
Column('foo_id', Integer, ForeignKey(foo.c.id)),
Column('test_id', Integer, ForeignKey(tests.c.id)))
bar = Table('bar',
Column('id', Integer, primary_key=True),
Column('data', String(20)))
test_bar = Table('test_bar',
Column('bar_id', Integer, ForeignKey(bar.c.id)),
Column('test_id', Integer, ForeignKey(tests.c.id)))
class Test(object):
_type = 'abstract'
def __init__(self, *args, **kwargs):
self.type = self._type
for key, value in kwargs.items():
setattr(self, key, value)
class Test1(Test):
_type = 'test1'
def __repr__(self):
return "Test1: %s %s %s" % (self.data1, repr([f for f in self.foos]), repr([b for b in self.bars]))
class Test2(Test):
_type = 'test2'
def __repr__(self):
return "Test2: %s %s" % (self.data2, repr([f for f in self.foos]))
class Foo(object):
pass
class Bar(object):
pass
class TestLoader( MapperExtension ):
def create_instance(self, mapper, row, imap, class_):
if row['tests_type'] == 'test1': return Test1()
if row['tests_type'] == 'test2': return Test2()
raise "InvalidType", "'%s' is an invalid type. " % row['tests_type']
def populate_instance(self, mapper, instance, row, identitykey, imap, isnew):
print [c for c in row.keys()]
if row['tests_type'] =='test1':
Test1.mapper.populate_instance(instance, row, identitykey, imap, isnew, frommapper=mapper)
return False
if row['tests_type'] =='test2':
Test2.mapper.populate_instance(instance, row, identitykey, imap, isnew, frommapper=mapper)
return False
return True
testext = TestLoader()
assign_mapper(Foo, foo)
assign_mapper(Bar, bar)
Test.mapper = mapper(Test, tests, extension=testext, properties={
'foos' : relation(Foo, secondary=test_foo)
})
Test1.mapper = mapper(Test1, tests, inherits=Test.mapper, properties = {
'bars': relation(Bar, secondary=test_bar)
})
Test2.mapper = mapper(Test2, tests, inherits=Test.mapper)
global_connect('sqlite://', echo=True)
tests.create()
foo.create()
bar.create()
test_foo.create()
test_bar.create()
first = Test1(data1=5)
second = Test2(data2="hi")
first.foos.append(Foo(data='foo1'))
first.bars.append(Bar(data='bar1'))
second.foos.append(Foo(data='foo2'))
print "----------------\nCOMMIT\n"
objectstore.commit()
def get_test(id):
t1key = Test1.mapper.identity_key(id)
t2key = Test2.mapper.identity_key(id)
if objectstore.has_key(t1key):
return Test1.mapper.get(id)
elif objectstore.has_key(t2key):
return Test2.mapper.get(id)
else:
return Test.mapper.get(id)
print "--------------\nGET\n"
print get_test(1)
objectstore.clear()
print "--------------\nSELECTALL\n"
all = Test.mapper.select()
for test_instance in all:
print test_instance
On Mar 26, 2006, at 8:09 PM, Michael Carter wrote: It seems that this problem is giving me more trouble than I originally thought. If I create a many-to-many relation between the baseclass Test and some other class Foo to get the attribute foos, then it doesn't work with Test1 and Test2 instances. a = Test1(); a.foos.append(Foo()); objectstore.commit() => only adds the new Foo() but doesn't make an entry into the tests_foos table. |

