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 [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.