do it like this for now:
class FilterMixin(object):
@declared_attr
def _filters(cls):
cls.filters = association_proxy('_filters', 'filter')
return relationship(cls.filter_class,
cascade='all,delete,delete-orphan')
there's a patch for 0.8 only in http://www.sqlalchemy.org/trac/ticket/2517 .
On Jun 20, 2012, at 1:13 PM, Wichert Akkerman wrote:
> I am struggling a little bit with mixin classes. The pattern I am trying to
> implement is a mixin-class that adds a list of validated search queries to a
> model. A minimised version of the code is below. The problem I am running
> into is that putting an association_proxy on a mixin class does not appear to
> work here: it always picks the first seen class type to create new values
> instead of picking up what the relationship of the current instance requires.
> With the example below that results in this error:
>
> AssertionError: Attribute '_filters' on class '<class '__main__.TypeB'>'
> doesn't handle objects of type'<class '__main__.FilterA'>'
>
>
>
> My initial though was that this might be fixed by making the
> association_proxy instance itself a declared_attr, but that results in other
> problems.
>
> Is there an alternative way to implement this, or is this a bug in the
> declarative logic?
>
>
> from sqlalchemy import *
> from sqlalchemy.orm import *
> from sqlalchemy.ext.associationproxy import association_proxy
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy.ext.declarative import declared_attr
>
>
> metadata = MetaData()
> BaseObject = declarative_base(metadata=metadata)
>
> class BaseFilter(BaseObject):
> __abstract__ = True
>
> id = Column(Integer(), primary_key=True, autoincrement=True)
> filter = Column(UnicodeText(), nullable=False)
>
> @declared_attr
> def __tablename__(cls):
> return '%s_filter' % cls.parent_tablename
>
> @declared_attr
> def parent_id(cls):
> return Column(Integer(),
> ForeignKey('%s.id' % cls.parent_tablename,
> ondelete='CASCADE', onupdate='CASCADE'),
> nullable=False, index=True)
>
> def __init__(self, filter, **kw):
> super(BaseFilter, self).__init__(filter=filter, **kw)
>
> @validates('filter')
> def validate_filter(self, key, value):
> assert len(value)> 2
> return value
>
>
> class FilterA(BaseFilter):
> parent_tablename = 'type_a'
>
>
> class FilterB(BaseFilter):
> parent_tablename = 'type_b'
>
>
> class FilterMixin(object):
> @declared_attr
> def _filters(cls):
> return relationship(cls.filter_class,
> cascade='all,delete,delete-orphan')
>
> filters = association_proxy('_filters', 'filter')
>
> # @declared_attr
> # def filters(cls):
> # return association_proxy('_filters', 'filter')
>
>
> class TypeA(BaseObject, FilterMixin):
> __tablename__ = 'type_a'
> filter_class = FilterA
> id = Column(Integer(), primary_key=True, autoincrement=True)
>
> class TypeB(BaseObject, FilterMixin):
> __tablename__ = 'type_b'
> filter_class = FilterB
> id = Column(Integer(), primary_key=True, autoincrement=True)
>
>
> engine = create_engine('sqlite://')
> metadata.bind = engine
> metadata.create_all()
> Session = sessionmaker(bind=engine)
> session = Session()
>
> session.add(TypeA(filters=[u'foo']))
> session.add(TypeB(filters=[u'foo']))
> session.flush()
>
>
> --
> 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.
>
--
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.