On Mar 27, 2010, at 5:58 AM, Chris Withers wrote: > avdd wrote: >> In a metaclass's __init__, the attributes have already been placed on >> the class, so mutating the attributes dict has no effect. > > Spot on. SA fudged this prior to 0.6beta so you could get away with shoving > stuff in dict_, you now can't...
OK. Simply assigning something to cls.id now works. Here is my current production code: class ClassDefaults(DeclarativeMeta): def __init__(cls,classname, bases, dict_): if not ( dict_.has_key('__mapper_args__') and dict_['__mapper_args__'].has_key('polymorphic_identity') ): seqprefix = getattr(cls,'__tablename__',None) cls.id = PrimaryKey(seqprefix=seqprefix) return DeclarativeMeta.__init__(cls, classname, bases, dict_) However, this new approach is incompatible with 0.6_beta1 (and earlier, I assume.) >>> class ClassDefaults(DeclarativeMeta): >>> def __init__(cls,classname, bases, dict_): >>> seqprefix = getattr(cls,'__tablename__',None) > > When are you expecting cls not to have a tablename? The line "Base = declarative_base(metaclass=ClassDefaults)" requires this. ext/declarative.py (at least in 0.6_beta1+) has a "return metaclass(name, bases, class_dict)" on line 764 which causes the constructor to be called, prior to assignment of a __tablename__. If I change my line above to "seqprefix = cls.__tablename__", I get a traceback. > Using tabs for intentation is evil. I view choice of indentation as an issue of personal preference rather than one that has larger moral and religious implications. I have always preferred tabs over spaces for indent as I find them much easier to work with. > cls.id = Column(Integer, Sequence(cls.__tablename__, optional=True), > primary_key=True) This is related to the possibility that the __tablename__ can be undefined. When seqprefix is None, my PrimaryKey method will still return a primary key, but it will have a unique sequence name based on a global, incrementing integer. I do welcome any improvements to SQLAlchemy that may make this particular usage case less complicated, but currently it appears that all my little tricks are required. > > http://www.sqlalchemy.org/docs/reference/ext/declarative.html#mix-in-classes > > ...I don't think they'll help here 'cos you're computing based on > __tablename__. Right. Mix-ins look wonderful but they don't work for all cases. > Of course, nowadays, I tend to have tablename computed in a mix-in that does > all my common stuff: > > class BaseMixin(object): > __table_args__ = {'mysql_engine':'InnoDB'} > @classproperty > def __tablename__(cls): > return cls.__name__.lower() > id = Column(Integer,primary_key=True) I'm wondering if this would work for my purposes then: class BaseMixin(object): @classproperty def __tablename__(cls): return cls.__name__ id = Column(Integer, Sequence(cls.__name__, Optional=True), primary_key=True) class Foo(Base,BaseMixin): # will I get an "id" + sequence from the BaseMixin? __name__ = "foo" foo = Column(String(80), nullable=False) Haven't tried it yet. :) -Daniel -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@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.