using @declared_attr to define a column in an actual class (non-mixin)

296 views
Skip to first unread message

Yap Sok Ann

unread,
Sep 23, 2011, 12:48:34 AM9/23/11
to sqlalchemy
With this code:

from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.schema import Column
from sqlalchemy.types import Integer, String

Base = declarative_base()


class Mixin(object):
@declared_attr
def attr2(cls):
return Column(String(20), nullable=False)


class Test(Base, Mixin):
__tablename__ = 'test'

id = Column(Integer, primary_key=True)

@declared_attr
def attr1(cls):
return Column(String(20), nullable=False)


if __name__ == '__main__':
print Test.attr1.__class__
print Test.attr2.__class__


Test.attr1 will be a sqlalchemy.schema.Column, while Test.attr2 will
be a sqlalchemy.orm.attributes.InstrumentedAttribute. Why are they
behave differently?

Anyway, what I want to achieve is to selectively define a column based
on some external flag, so I was trying to put in if..else block inside
@declared_attr to return either None or Column. Is there a better way
to do it, e.g. using a metaclass?

Thanks.

Michael Bayer

unread,
Sep 23, 2011, 1:36:13 AM9/23/11
to sqlal...@googlegroups.com
@declared_attr when used for attributes outside of __table_args__, __tablename__ and __mapper_args__ is only recognized on a mixin, or on a class that uses a new directive "__abstract__ = True". It's skipped on mapped classes when used for plain column attributes since inheriting from a mapped class means you're using mapper inheritance - and in the usual case of single- or joined-table inheritance, the subclass specifically should not get copies of columns on the superclass. So really @declared_attr returning a column on the mapped class should be raising an error here, perhaps I'll make it emit a warning for the time being since it will not do anything useful.

If you'd like to put a non-mixin class in the middle of your hierarchy that can define columns that immediate subclasses should have, use the tip of 0.7 (0.7.3 not released yet) and put the directive "__abstract__ = True" on the class - the @declared_attr's on columns should be recognized in that case. You wouldn't want to have "__tablename__ = 'test'" on such a class either since it isn't mapped.

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

Yap Sok Ann

unread,
Sep 23, 2011, 6:35:20 AM9/23/11
to sqlalchemy
Thanks for clearing that up. "__abstract__ = True" looks like a nice
addition. In this case, I decided to go with the metaclass approach,
i.e. declaring the attributes as usual, and then delete them if
necessary in the metaclass.
Reply all
Reply to author
Forward
0 new messages