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)))
 
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)))
 
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'])
    )
 
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'])
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

Reply via email to