In 0.6_beta2, the following code is not properly adding a primary key Column via DeclarativeMeta which calls my PrimaryKey() function:
def PrimaryKey(seqprefix):
return Column(Integer, Sequence(seqprefix, optional=True), primary_key=True)
class ClassDefaults(DeclarativeMeta):
def __init__(cls,classname, bases, dict_):
seqprefix = getattr(cls,'__tablename__',None)
dict_['id'] = PrimaryKey(seqprefix=seqprefix)
return DeclarativeMeta.__init__(cls, classname, bases, dict_)
Base = declarative_base(metaclass=ClassDefaults)
class Location(Base):
__tablename__ = 'location'
parent_id = Column(Integer, ForeignKey('location.id'))
parent = relation('Location', backref=backref('children'), remote_side='location.c.id')
name = UniqueString(25)
desc = Column(String(80))
SQLAlchemy 0.6_beta2 complains on table initialization:
File "/usr/lib64/python2.6/site-packages/sqlalchemy/orm/mapper.py", line 444, in _configure_pks
"key columns for mapped table '%s'" % (self, self.mapped_table.description))
sqlalchemy.exc.ArgumentError: Mapper Mapper|Location|location could not assemble any primary key columns for mapped table 'location'
This worked under 0.6_beta1 (and likely earlier versions of SQLAlchemy).
Can someone send me some code similar to above that works with 0.6_beta2, or is this a bug in beta2?
Thanks,
Daniel
Try setting the id attribute directly:
self.id = PrimaryKey(...)
Spot on. SA fudged this prior to 0.6beta so you could get away with
shoving stuff in dict_, you now can't...
>> def PrimaryKey(seqprefix):
>> return Column(Integer, Sequence(seqprefix, optional=True), primary_key=True)
>>
>> class ClassDefaults(DeclarativeMeta):
>> def __init__(cls,classname, bases, dict_):
>> seqprefix = getattr(cls,'__tablename__',None)
When are you expecting cls not to have a tablename?
Using tabs for intentation is evil.
>> dict_['id'] = PrimaryKey(seqprefix=seqprefix)
Why not just have:
cls.id = Column(Integer, Sequence(cls.__tablename__, optional=True),
primary_key=True)
?
You might also benefit from reading:
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__.
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)
cheers,
Chris
--
Simplistix - Content Management, Batch Processing & Python Consulting
- http://www.simplistix.co.uk
avdd wrote:In a metaclass's __init__, the attributes have already been placed onthe 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...
class ClassDefaults(DeclarativeMeta):def __init__(cls,classname, bases, dict_):seqprefix = getattr(cls,'__tablename__',None)
When are you expecting cls not to have a tablename?
Using tabs for intentation is evil.
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__.
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)