I've been spending the past few hours trying to
understand/debug a problem I'm having with my single-table inheritance mapping.
I am attaching the code for a test case that results in an attribute error. The
relevant pieces (I think) are shown below. They result in an AttributeError in
the sessionlib.attribute_manager.reset_class_managed on the first inherited
mapper of Node (Algorithm, or Parameter if commenting out
Algorithm)
projects_table = Table('projects', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(40)))
Column('id', Integer, primary_key=True),
Column('name', String(40)))
versions_table = Table('versions', metadata,
Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True),
Column('id', Integer, primary_key=True),
Column('date', DateTime),
Column('comment', String(300)))
Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True),
Column('id', Integer, primary_key=True),
Column('date', DateTime),
Column('comment', String(300)))
node_types = {'Node':0, 'Algorithm':1,'Parameter':2}
nodes_table = Table('nodes', metadata,
Column('project_id', Integer, ForeignKey('projects.id')),
Column('id', Integer, primary_key=True),
Column('type', Integer),
Column('name', String(30)),
Column('description', String(80)),
Column('comments', String),
Column('start_version_id', Integer),
Column('end_version_id', Integer),
Column('sub_project_id', Integer, ForeignKey('projects.id')),
Column('sub_project_version_id', Integer),
Column('parameter_type', Integer),
Column('value', String),
Column('previous_id', Integer, ForeignKey('nodes.id')),
ForeignKeyConstraint(
['project_id','start_version_id'],
['versions.project_id','versions.id']
),
ForeignKeyConstraint(
['project_id','end_version_id'],
['versions.project_id','versions.id']
),
ForeignKeyConstraint(
['sub_project_id','sub_project_version_id'],
['versions.project_id','versions.id'])
)
Column('project_id', Integer, ForeignKey('projects.id')),
Column('id', Integer, primary_key=True),
Column('type', Integer),
Column('name', String(30)),
Column('description', String(80)),
Column('comments', String),
Column('start_version_id', Integer),
Column('end_version_id', Integer),
Column('sub_project_id', Integer, ForeignKey('projects.id')),
Column('sub_project_version_id', Integer),
Column('parameter_type', Integer),
Column('value', String),
Column('previous_id', Integer, ForeignKey('nodes.id')),
ForeignKeyConstraint(
['project_id','start_version_id'],
['versions.project_id','versions.id']
),
ForeignKeyConstraint(
['project_id','end_version_id'],
['versions.project_id','versions.id']
),
ForeignKeyConstraint(
['sub_project_id','sub_project_version_id'],
['versions.project_id','versions.id'])
)
projects_table.create(checkfirst=True)
versions_table.create(checkfirst=True)
nodes_table.create(checkfirst=True)
versions_table.create(checkfirst=True)
nodes_table.create(checkfirst=True)
class Project(object):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
class Version(object):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
self.date = self.date or time.strftime("%Y-%m-%d %H:%M:%S")
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
self.date = self.date or time.strftime("%Y-%m-%d %H:%M:%S")
class Node(object):
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
def __init__(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
class Algorithm(Node):
pass
pass
class Parameter(Node):
pass
pass
class VersionKeyMapper(MapperExtension):
def before_insert(self, mapper, connection, instance):
versions_t = mapper.select_table
s = select(
[func.max(versions_t.c.id)+1],
versions_t.c.project_id==instance.project_id
)
r = s.execute()
new_id = r.fetchone()[0]
instance.id = new_id or 1
def before_insert(self, mapper, connection, instance):
versions_t = mapper.select_table
s = select(
[func.max(versions_t.c.id)+1],
versions_t.c.project_id==instance.project_id
)
r = s.execute()
new_id = r.fetchone()[0]
instance.id = new_id or 1
Version.mapper = mapper(Version,versions_table,
extension=VersionKeyMapper())
Project.mapper = mapper(Project,projects_table, properties =
{
'versions' : relation(Version, backref = 'project')
})
'versions' : relation(Version, backref = 'project')
})
Node.mapper = mapper(Node, nodes_table,
polymorphic_on=nodes_table.c.type,
polymorphic_identity=node_types['Node'],
properties = {
'project' : relation(Project,
primaryjoin=nodes_table.c.project_id == Project.c.id,
uselist=False,
foreignkey=Project.c.id),
'start_version' : relation(Version,
primaryjoin=and_(
nodes_table.c.project_id == Version.c.project_id,
nodes_table.c.start_version_id == Version.c.id
),backref='start_nodes'),
'end_version' : relation(Version,
primaryjoin=and_(
nodes_table.c.project_id == Version.c.project_id,
nodes_table.c.end_version_id == Version.c.id
),backref='end_nodes'),
'previous' : relation(Node,
primaryjoin=nodes_table.c.previous_id == nodes_table.c.id,
backref='next',uselist=False)
})
polymorphic_on=nodes_table.c.type,
polymorphic_identity=node_types['Node'],
properties = {
'project' : relation(Project,
primaryjoin=nodes_table.c.project_id == Project.c.id,
uselist=False,
foreignkey=Project.c.id),
'start_version' : relation(Version,
primaryjoin=and_(
nodes_table.c.project_id == Version.c.project_id,
nodes_table.c.start_version_id == Version.c.id
),backref='start_nodes'),
'end_version' : relation(Version,
primaryjoin=and_(
nodes_table.c.project_id == Version.c.project_id,
nodes_table.c.end_version_id == Version.c.id
),backref='end_nodes'),
'previous' : relation(Node,
primaryjoin=nodes_table.c.previous_id == nodes_table.c.id,
backref='next',uselist=False)
})
Project.mapper.add_property('nodes', relation(Node,
primaryjoin=Node.c.project_id == Project.c.id,
foreignkey=Node.c.project_id))
primaryjoin=Node.c.project_id == Project.c.id,
foreignkey=Node.c.project_id))
Algorithm.mapper = mapper(Algorithm, inherits=Node.mapper,
polymorphic_identity=node_types['Algorithm'],
properties = {
'sub_project' : relation(Project,
primaryjoin=(nodes_table.c.sub_project_id == Project.c.id),
foreignkey=Project.c.id,
backref = 'alg_nodes_using'),
'sub_project_version' : relation(Version,
primaryjoin=and_(
Node.c.sub_project_id == Version.c.project_id,
Node.c.sub_project_version_id == Version.c.id
), backref = 'alg_nodes_using')
})
polymorphic_identity=node_types['Algorithm'],
properties = {
'sub_project' : relation(Project,
primaryjoin=(nodes_table.c.sub_project_id == Project.c.id),
foreignkey=Project.c.id,
backref = 'alg_nodes_using'),
'sub_project_version' : relation(Version,
primaryjoin=and_(
Node.c.sub_project_id == Version.c.project_id,
Node.c.sub_project_version_id == Version.c.id
), backref = 'alg_nodes_using')
})
Parameter.mapper = mapper(Parameter, inherits=Node.mapper,
polymorphic_identity=node_types['Parameter'])
polymorphic_identity=node_types['Parameter'])
from sqlalchemy import * import time import os try: os.remove('test.db') except OSError: pass
db = create_engine('sqlite:///test.db') metadata = BoundMetaData(db) # Define the tables projects_table = Table('projects', metadata, Column('id', Integer, primary_key=True), Column('name', String(40))) node_types = {'Node':0, 'Algorithm':1,'Parameter':2} nodes_table = Table('nodes', metadata, Column('project_id', Integer, ForeignKey('projects.id')), Column('id', Integer, primary_key=True), Column('type', Integer), Column('name', String(30)), Column('description', String(80)), Column('comments', String), Column('start_version_id', Integer), Column('end_version_id', Integer), Column('sub_project_id', Integer, ForeignKey('projects.id')), Column('sub_project_version_id', Integer), Column('parameter_type', Integer), Column('value', String), Column('previous_id', Integer, ForeignKey('nodes.id')), ForeignKeyConstraint( ['project_id','start_version_id'], ['versions.project_id','versions.id'] ), ForeignKeyConstraint( ['project_id','end_version_id'], ['versions.project_id','versions.id'] ), ForeignKeyConstraint( ['sub_project_id','sub_project_version_id'], ['versions.project_id','versions.id']) ) edges_table = Table('edges', metadata, Column('project_id', Integer, ForeignKey('projects.id')), Column('id', Integer, primary_key=True), Column('type', Integer), Column('name', String(30)), Column('from_node_id', Integer, ForeignKey('nodes.id')), Column('to_node_id', Integer, ForeignKey('nodes.id')), Column('start_version_id', Integer, ForeignKey('versions.id')), Column('end_version_id', Integer, ForeignKey('versions.id')), Column('constraint_id', Integer, ForeignKey('contraints.id')), Column('previous_id', Integer, ForeignKey('edges.id'))) versions_table = Table('versions', metadata, Column('project_id', Integer, ForeignKey('projects.id'), primary_key=True), Column('id', Integer, primary_key=True), Column('date', DateTime), Column('comment', String(300))) constraints_table = Table('constraints', metadata, Column('id', Integer, primary_key=True), Column('type', Integer), Column('params', String(100))) # Echo db interactions metadata.engine.echo = True # Create the tables if they don't already exist (checkfirst=True) projects_table.create(checkfirst=True) versions_table.create(checkfirst=True) nodes_table.create(checkfirst=True) class Project(object): def __init__(self, **kwargs): for key, value in kwargs.iteritems(): setattr(self, key, value) class Version(object): def __init__(self, **kwargs): for key, value in kwargs.iteritems(): setattr(self, key, value) self.date = self.date or time.strftime("%Y-%m-%d %H:%M:%S") class Node(object): def __init__(self, **kwargs): for key, value in kwargs.iteritems(): setattr(self, key, value) class Algorithm(Node): pass class Parameter(Node): pass class VersionKeyMapper(MapperExtension): def before_insert(self, mapper, connection, instance): versions_t = mapper.select_table s = select( [func.max(versions_t.c.id)+1], versions_t.c.project_id==instance.project_id ) r = s.execute() new_id = r.fetchone()[0] instance.id = new_id or 1 Version.mapper = mapper(Version,versions_table, extension=VersionKeyMapper()) Project.mapper = mapper(Project,projects_table, properties = { 'versions' : relation(Version, backref = 'project') }) Node.mapper = mapper(Node, nodes_table, polymorphic_on=nodes_table.c.type, polymorphic_identity=node_types['Node'], properties = { 'project' : relation(Project, primaryjoin=nodes_table.c.project_id == Project.c.id, uselist=False, foreignkey=Project.c.id), 'start_version' : relation(Version, primaryjoin=and_( nodes_table.c.project_id == Version.c.project_id, nodes_table.c.start_version_id == Version.c.id ),backref='start_nodes'), 'end_version' : relation(Version, primaryjoin=and_( nodes_table.c.project_id == Version.c.project_id, nodes_table.c.end_version_id == Version.c.id ),backref='end_nodes'), 'previous' : relation(Node, primaryjoin=nodes_table.c.previous_id == nodes_table.c.id, backref='next',uselist=False) }) Project.mapper.add_property('nodes', relation(Node, primaryjoin=Node.c.project_id == Project.c.id, foreignkey=Node.c.project_id)) Algorithm.mapper = mapper(Algorithm, inherits=Node.mapper, polymorphic_identity=node_types['Algorithm'], properties = { 'sub_project' : relation(Project, primaryjoin=(nodes_table.c.sub_project_id == Project.c.id), foreignkey=Project.c.id, backref = 'alg_nodes_using'), 'sub_project_version' : relation(Version, primaryjoin=and_( Node.c.sub_project_id == Version.c.project_id, Node.c.sub_project_version_id == Version.c.id ), backref = 'alg_nodes_using') }) Parameter.mapper = mapper(Parameter, inherits=Node.mapper, polymorphic_identity=node_types['Parameter']) session = create_session(bind_to=db) #Make test data: p = Project('test') p.versions.append(Version('first version')) # Comment out other version adds before flush because of # sequential dependency error #p.versions.append(Version('second version')) #p.versions.append(Version('third version')) session.save(p) session.flush() #n = Node() #n.name='New node, v1' #v = session.query(Version).select()[0] #v.start_nodes.append(n)
------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________ Sqlalchemy-users mailing list Sqlalchemy-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users