Re: [sqlalchemy] mixing association proxies and mixin classes

2012-06-21 Thread Wichert Akkerman

That works like a charm, thanks!


On 06/21/2012 12:46 AM, Michael Bayer wrote:

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 sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
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 sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] mixing association proxies and mixin classes

2012-06-20 Thread Wichert Akkerman
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 sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] mixing association proxies and mixin classes

2012-06-20 Thread Michael Bayer
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 sqlalchemy@googlegroups.com.
 To unsubscribe from this group, send email to 
 sqlalchemy+unsubscr...@googlegroups.com.
 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 sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.