TaskMixin.tasks places a relationship named "task_of" onto the "Task" class via 
the backref directive.   Only one relationship of this name can exist on the 
parent class, and a relationship is only configurable against a single class.   
This single class can be of course a common base for many subclasses, but in 
this case you're attempting to create two "task_of" relationships, one 
hardwired to TaskableClassA and the other hardwired to TaskableClassB.

It seems likely you'd like "task_of" to link to both classes and load 
polymorphically - so TaskableClassA and TaskableClassB should both inherit from 
a common base, with no __tablename__, such as TaskableClassBase - that class 
then uses TaskMixin to establish behavior common to both.

Of course you don't really need the TaskMixin here since it can only be used 
once with that backref on it.

you can try the modified versions attached - the first uses TaskMixin the 
second removes it.




On Sep 4, 2011, at 3:18 PM, Erkan Özgür Yılmaz wrote:

> from sqlalchemy import Column, ForeignKey, Integer, String
> from sqlalchemy.orm import relationship, validates
> from sqlalchemy.ext import declarative
> from sqlalchemy.ext.declarative import declarative_base, declared_attr
> 
> Base = declarative_base()
> 
> # The Base Class
> ########################################################################
> class SimpleEntity(Base):
>     __tablename__ = "SimpleEntities"
>     id = Column("id", Integer, primary_key=True)
>     
>     entity_type = Column("db_entity_type", String(128), nullable=False)
>     __mapper_args__ = {
>         "polymorphic_on": entity_type,
>         "polymorphic_identity": "SimpleEntity",
>     }
>     
>     name = Column(String(256), nullable=False)
>     
>     #----------------------------------------------------------------------
>     def __init__(self, name=None, **kwargs):
>         
>         self.name = name
> 
> ########################################################################
> class Task(SimpleEntity):
>     __tablename__ = "Tasks"
>     task_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
>                      primary_key=True)
>     __mapper_args__ = {"polymorphic_identity": "Task",
>                        "inherit_condition": task_id==SimpleEntity.id}
>     
>     task_of_id = Column(Integer,
>                         ForeignKey("SimpleEntities.id")
>                         )
>     
>     #----------------------------------------------------------------------
>     def __init__(self, task_of=None, **kwargs):
>         super(Task, self).__init__(**kwargs)
>         self.task_of = task_of
> 
> ########################################################################
> class TaskMixin(object): # The mixin
>     def __init__(self, tasks=None, **kwargs):
>         if tasks is None:
>             tasks = []
>         self.tasks = tasks
>     
>     #----------------------------------------------------------------------
>     @declared_attr
>     def tasks(cls):
>         return relationship(
>             "Task",
>             primaryjoin="Tasks.c.task_of_id==SimpleEntities.c.id",
>             backref="task_of",
>         )
> 
> 
> ########################################################################
> # example class 1 - defining only one class with TaskMixin doesn't create
> # any problem
> class TaskableClassA(SimpleEntity, TaskMixin):
>     __tablename__ = "TaskableAs"
>     __mapper_args__ = {"polymorphic_identity": "TaskableClassA"}
>     taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
>                               primary_key=True)
>     
>     #----------------------------------------------------------------------
>     def __init__(self, **kwargs):
>         super(SimpleEntity, self).__init__(**kwargs)
>         TaskMixin.__init__(self, **kwargs)
> 
> #######################################################################
> # example class 2 - which creates the problem
> class TaskableClassB(SimpleEntity, TaskMixin):
>     __tablename__ = "TaskableBs"
>     __mapper_args__ = {"polymorphic_identity": "TaskableClassB"}
>     taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
>                               primary_key=True)
>     
>     #----------------------------------------------------------------------
>     def __init__(self, **kwargs):
>         super(SimpleEntity, self).__init__(**kwargs)
>         TaskMixin.__init__(self, **kwargs)
> 
> a_taskable_object = TaskableClassA(name="taskable test object")
> task1 = Task(name="Test Task1", task_of=a_taskable_object)
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.orm import relationship, validates, Session
from sqlalchemy.ext import declarative
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

# The Base Class
########################################################################
class SimpleEntity(Base):
    __tablename__ = "SimpleEntities"
    id = Column("id", Integer, primary_key=True)

    entity_type = Column("db_entity_type", String(128), nullable=False)
    __mapper_args__ = {
        "polymorphic_on": entity_type,
        "polymorphic_identity": "SimpleEntity",
    }

    name = Column(String(256), nullable=False)

    #----------------------------------------------------------------------
    def __init__(self, name=None, **kwargs):

        self.name = name

########################################################################
class Task(SimpleEntity):
    __tablename__ = "Tasks"
    task_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                     primary_key=True)
    __mapper_args__ = {"polymorphic_identity": "Task",
                       "inherit_condition": task_id==SimpleEntity.id}

    task_of_id = Column(Integer,
                        ForeignKey("SimpleEntities.id")
                        )

    #----------------------------------------------------------------------
    def __init__(self, task_of=None, **kwargs):
        super(Task, self).__init__(**kwargs)
        self.task_of = task_of

########################################################################
class TaskMixin(object): # The mixin
    def __init__(self, tasks=None, **kwargs):
        if tasks is None:
            tasks = []
        self.tasks = tasks

    #----------------------------------------------------------------------
    @declared_attr
    def tasks(cls):
        return relationship(
            "Task",
            primaryjoin="Tasks.c.task_of_id==SimpleEntities.c.id",
            backref="task_of",
        )


class TaskableBase(SimpleEntity, TaskMixin):
    pass

########################################################################
# example class 1 - defining only one class with TaskMixin doesn't create
# any problem
class TaskableClassA(TaskableBase):
    __tablename__ = "TaskableAs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassA"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)

    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)
        TaskMixin.__init__(self, **kwargs)

#######################################################################
# example class 2 - which creates the problem
class TaskableClassB(TaskableBase):
    __tablename__ = "TaskableBs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassB"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)

    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)
        TaskMixin.__init__(self, **kwargs)

e = create_engine('sqlite://', echo=True)
Base.metadata.create_all(e)

s = Session(e)
s.add_all([
    TaskableClassA(name="ta1", tasks=[Task(name="tt1"), Task(name="tt2")]),
    TaskableClassB(name="tb1", tasks=[Task(name="tt3"), Task(name="tt4")]),
])
s.commit()

tasks = s.query(Task).order_by(Task.name).all()

def eq_(a, b):
    assert a == b, "%s != %s" % (a, b)
eq_([t.task_of.name for t in tasks], ["ta1", "ta1", "tb1", "tb1"])
eq_([type(t.task_of) for t in tasks], [TaskableClassA,TaskableClassA,TaskableClassB,TaskableClassB,])
from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.orm import relationship, validates, Session
from sqlalchemy.ext import declarative
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

# The Base Class
########################################################################
class SimpleEntity(Base):
    __tablename__ = "SimpleEntities"
    id = Column("id", Integer, primary_key=True)

    entity_type = Column("db_entity_type", String(128), nullable=False)
    __mapper_args__ = {
        "polymorphic_on": entity_type,
        "polymorphic_identity": "SimpleEntity",
    }

    name = Column(String(256), nullable=False)

    #----------------------------------------------------------------------
    def __init__(self, name=None, **kwargs):

        self.name = name

########################################################################
class Task(SimpleEntity):
    __tablename__ = "Tasks"
    task_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                     primary_key=True)
    __mapper_args__ = {"polymorphic_identity": "Task",
                       "inherit_condition": task_id==SimpleEntity.id}

    task_of_id = Column(Integer,
                        ForeignKey("SimpleEntities.id")
                        )

    #----------------------------------------------------------------------
    def __init__(self, task_of=None, **kwargs):
        super(Task, self).__init__(**kwargs)
        self.task_of = task_of

class TaskableBase(SimpleEntity):
    def __init__(self, tasks=None, **kwargs):
        if tasks is None:
            tasks = []
        self.tasks = tasks

    tasks = relationship(
            "Task",
            primaryjoin="Tasks.c.task_of_id==SimpleEntities.c.id",
            backref="task_of",
        )

########################################################################
# example class 1 - defining only one class with TaskMixin doesn't create
# any problem
class TaskableClassA(TaskableBase):
    __tablename__ = "TaskableAs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassA"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)

    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)

#######################################################################
# example class 2 - which creates the problem
class TaskableClassB(TaskableBase):
    __tablename__ = "TaskableBs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassB"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)

    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)

e = create_engine('sqlite://', echo=True)
Base.metadata.create_all(e)

s = Session(e)
s.add_all([
    TaskableClassA(name="ta1", tasks=[Task(name="tt1"), Task(name="tt2")]),
    TaskableClassB(name="tb1", tasks=[Task(name="tt3"), Task(name="tt4")]),
])
s.commit()

tasks = s.query(Task).order_by(Task.name).all()

def eq_(a, b):
    assert a == b, "%s != %s" % (a, b)
eq_([t.task_of.name for t in tasks], ["ta1", "ta1", "tb1", "tb1"])
eq_([type(t.task_of) for t in tasks], [TaskableClassA,TaskableClassA,TaskableClassB,TaskableClassB,])


On Sep 4, 2011, at 3:18 PM, Erkan Özgür Yılmaz wrote:

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship, validates
from sqlalchemy.ext import declarative
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

# The Base Class
########################################################################
class SimpleEntity(Base):
    __tablename__ = "SimpleEntities"
    id = Column("id", Integer, primary_key=True)
    
    entity_type = Column("db_entity_type", String(128), nullable=False)
    __mapper_args__ = {
        "polymorphic_on": entity_type,
        "polymorphic_identity": "SimpleEntity",
    }
    
    name = Column(String(256), nullable=False)
    
    #----------------------------------------------------------------------
    def __init__(self, name=None, **kwargs):
        
        self.name = name

########################################################################
class Task(SimpleEntity):
    __tablename__ = "Tasks"
    task_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                     primary_key=True)
    __mapper_args__ = {"polymorphic_identity": "Task",
                       "inherit_condition": task_id==SimpleEntity.id}
    
    task_of_id = Column(Integer,
                        ForeignKey("SimpleEntities.id")
                        )
    
    #----------------------------------------------------------------------
    def __init__(self, task_of=None, **kwargs):
        super(Task, self).__init__(**kwargs)
        self.task_of = task_of

########################################################################
class TaskMixin(object): # The mixin
    def __init__(self, tasks=None, **kwargs):
        if tasks is None:
            tasks = []
        self.tasks = tasks
    
    #----------------------------------------------------------------------
    @declared_attr
    def tasks(cls):
        return relationship(
            "Task",
            primaryjoin="Tasks.c.task_of_id==SimpleEntities.c.id",
            backref="task_of",
        )


########################################################################
# example class 1 - defining only one class with TaskMixin doesn't create
# any problem
class TaskableClassA(SimpleEntity, TaskMixin):
    __tablename__ = "TaskableAs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassA"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)
    
    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)
        TaskMixin.__init__(self, **kwargs)

#######################################################################
# example class 2 - which creates the problem
class TaskableClassB(SimpleEntity, TaskMixin):
    __tablename__ = "TaskableBs"
    __mapper_args__ = {"polymorphic_identity": "TaskableClassB"}
    taskableClass_id = Column("id", Integer, ForeignKey("SimpleEntities.id"),
                              primary_key=True)
    
    #----------------------------------------------------------------------
    def __init__(self, **kwargs):
        super(SimpleEntity, self).__init__(**kwargs)
        TaskMixin.__init__(self, **kwargs)

a_taskable_object = TaskableClassA(name="taskable test object")
task1 = Task(name="Test Task1", task_of=a_taskable_object)


Reply via email to