On Jul 27, 2011, at 2:12 AM, Matthias wrote:

> Hello,
> 
> I'm currently writing my own version of the "magic" orm. I'd like it
> to generate id columns automatically. I tried it like shown below.
> 
> When using the code I get an exception:
> 
> ArgumentError: Mapper Mapper|Version|version could not assemble any
> primary key columns for mapped table 'Join object on content(55261328)
> and version(64443600)'
> 
> The problem seems to be in the WithId metaclass. When I put an id =
> Column(... primary = true) by hand on the Version class everything
> works. I was expecting the metaclass to do the same, but apparently
> there must be some difference,
> 
> Any idea how I can make the Base/Content/Version classes have id
> columns (which work with polymorphism) automatically? I'd like to stay
> away from mixin class all over the place.

Without looking closely, just the usage of a metaclass is frequently very 
difficult.  I know that you don't want to use a mixin, but why not specify your 
class as part of the declarative base ?    

Base = declarative_base(cls=WithIdBase)

This question has come up at least twice, maybe three times, in the last few 
weeks, so it seems as though the "mixin" section should get an explicit section 
about "you can use them as the Base also" - right now its only in the docstring.

Another use case that was identified was that of base classes that are not the 
"Base", but are in the middle of things.    We might add a function to 
declarative_base to build such a base, something like   mybase = 
declarative_base(cls=WithIdBase, derive_from_base=Base).   It would be a small 
patch.



> 
> -Matthias
> 
> 
> Code:
> 
> class WithId(DeclarativeMeta):
>    def __init__(cls,classname, bases, dict_):
>        if 'id' not in dict_:
>            dict_['id'] = Column('id', Integer,
> ForeignKey('content.id'), primary_key=True)
>        DeclarativeMeta.__init__(cls, classname, bases, dict_)
> 
> Base = declarative_base(metaclass=WithId)
> 
> class Content(db.Base):
>    id = db.Column('id', db.Integer, primary_key=True)
>    type = db.Column(db.String(250))
> 
>    @classmethod
>    def get_class_name(cls):
>        '''Convert CamelCase class name to underscores_between_words
>        table name.'''
>        name = cls.__name__
>        return (
>            name[0].lower() +
>            re.sub(r'([A-Z])', lambda m:"_" + m.group(0).lower(),
> name[1:])
>        )
> 
>    @db.declared_attr
>    def __tablename__(cls):
>        return cls.get_class_name()
> 
>    @db.declared_attr
>    def __mapper_args__(cls):
>        args = { 'polymorphic_identity' : cls.get_class_name() }
>        ContentClass = cls.__bases__[-1]
>        if ContentClass is db.Base:
>            args['polymorphic_on'] = cls.type
>        else:
>            args['inherit_condition'] = (cls.id == ContentClass.id)
>        return args
> 
> class Version(Content):
>    timestamp = Column(DateTime, default=datetime.datetime.now)
>    message = Column(UnicodeText)
>    #author = attribute(User, backref =
> collectionAttribute('authoredVersions'))
> 
> -- 
> 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.
> 

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

Reply via email to