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 |
