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.

Reply via email to