Thanks. I've got this working now, but am having trouble combining
polymorphism and multiple foreign keys to the same table. Here's
roughly what I'm doing:
class Entity(Base):
__tablename__ = 'entities'
id = Column(Integer, primary_key=True)
# ...bunch of columns...
type = Column(Unicode(20), nullable=False)
__mapper_args__ = {'polymorphic_on': type}
class Site(Entity): # Client account
__tablename__ = 'sites'
__mapper_args__ = {'polymorphic_identity': u'site'}
id = Column(Integer, ForeignKey('entities.id'), primary_key=True)
name = Column(Unicode(50), unique=True, nullable=False)
title = Column(Unicode(50), nullable=False)
# ...few more Entity derived models...
class Note(Entity):
__tablename__ = 'notes'
__mapper_args__ = {'polymorphic_identity': u'note',
'inherit_condition': (id == Entity.id)}
id = Column(Integer, ForeignKey('entities.id'), primary_key=True)
site_id = Column(Integer, ForeignKey('deals.id'), nullable=False)
site = relation(Site, foreign_keys=site_id,
primaryjoin=site_id == Site.id)
attached_to_id = Column(Integer, ForeignKey('entities.id'),
nullable=False)
attached_to = relation(Entity, foreign_keys=attached_to_id,
primaryjoin=attached_to_id == Entity.id,
backref=backref('notes', cascade='all, delete-
orphan'))
note = Column(Unicode(255), nullable=False)
I use Note.site to determine access rights and Note.attached_to to
determine containment. This declaration works until I try to delete a
site instance. SQLAlchemy throws up this exception:
...
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/sql/
compiler.py", line 287, in construct_params
pd[self.bind_names[bindparam]] = bindparam.value()
TypeError: id() takes exactly one argument (0 given)
However, if I remove the backref on attached_to, everything works
fine. If I move the backref to Note.site, it fails with the same
error. If I remove attached_to* and keep the backref on site, it works
again. I'm not sure what's wrong.
Here's the full traceback, for reference.
Traceback (most recent call last):
File "/home/jace/Projects/saproj/tests.py", line 76, in test_cascade
self.session.delete(site)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
session.py", line 1088, in delete
cascade_states = list(_cascade_state_iterator('delete', state))
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
session.py", line 1534, in _cascade_state_iterator
for (o, m) in mapper.cascade_iterator(cascade, state, **kwargs):
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
mapper.py", line 1229, in cascade_iterator
instance, instance_mapper, corresponding_state = iterator.next()
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
properties.py", line 703, in cascade_iterator
instances = state.value_as_iterable(self.key, passive=passive)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
state.py", line 128, in value_as_iterable
x = impl.get(self, dict_, passive=passive)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
attributes.py", line 377, in get
value = callable_(passive=passive)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
strategies.py", line 563, in __call__
result = q.all()
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
query.py", line 1286, in all
return list(self)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
query.py", line 1394, in __iter__
return self._execute_and_instances(context)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
query.py", line 1399, in _execute_and_instances
mapper=self._mapper_zero_or_none())
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/orm/
session.py", line 737, in execute
clause, params or {})
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/
base.py", line 1086, in execute
return Connection.executors[c](self, object, multiparams, params)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/
base.py", line 1149, in _execute_clauseelement
parameters=params
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/
base.py", line 1237, in __create_execution_context
return dialect.execution_ctx_cls(dialect, connection=self,
**kwargs)
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/engine/
default.py", line 355, in __init__
grp,m in enumerate(parameters)]
File "/usr/local/lib/python2.6/dist-packages/sqlalchemy/sql/
compiler.py", line 287, in construct_params
pd[self.bind_names[bindparam]] = bindparam.value()
TypeError: id() takes exactly one argument (0 given)
Thanks for the help.
On May 18, 10:42 pm, Michael Bayer <[email protected]> wrote:
> Don't use None for the Column type (i.e., detected as the "null" type). Put
> the type explicitly. This has been updated in the documentation recently
> since the "None" feature can't be fully supported at this time.
>
> On May 18, 2010, at 1:34 PM, Kiran Jonnalagadda wrote:
>
>
>
>
>
> > Is it possible to have multi-level polymorphism in SQLAlchemy? Here's
> > an example:
>
> > class Entity(Base):
> > __tablename__ = 'entities'
> > id = Column(Integer, primary_key=True)
> > created_at = Column(DateTime, default=datetime.utcnow,
> > nullable=False)
> > entity_type = Column(Unicode(20), nullable=False)
> > __mapper_args__ = {'polymorphic_on': entity_type}
>
> > class File(Entity):
> > __tablename__ = 'files'
> > id = Column(None, ForeignKey('entities.id'), primary_key=True)
> > filepath = Column(Unicode(255), nullable=False)
> > file_type = Column(Unicode(20), nullable=False)
> > __mapper_args__ = {'polymorphic_identity': u'file',
> > 'polymorphic_on': file_type)
>
> > class Image(File):
> > __mapper_args__ = {'polymorphic_identity': u'image'}
> > __tablename__ = 'images'
> > id = Column(None, ForeignKey('files.id'), primary_key=True)
> > width = Column(Integer)
> > height = Column(Integer)
>
> > When I call Base.metadata.create_all(), SQLAlchemy raises the
> > following error: NotImplementedError: Can't generate DDL for the null
> > type. This error goes away if I remove the Image model.
>
> > What gives?
>
> > I sense that declaring both polymorphic_identity and polymorphic_on in
> > File isn't doing the expected thing, but I'm not sure how else to do
> > this.
>
> --
> 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
> athttp://groups.google.com/group/sqlalchemy?hl=en.
--
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.