All pastes #936051 Raw Edit

Someone

public text v1 · immutable
·published 2008-03-10 02:24 UTC
rendered paste body

from sqlalchemy.schema import Table, SchemaItem, Column
from sqlalchemy.orm import synonym as _orm_synonym
from sqlalchemy.orm.interfaces import MapperProperty
from sqlalchemy.orm.properties import PropertyLoader
from sqlalchemy import exceptions
    
class Thingy(type):
    def __init__(cls, classname, bases, dict_):
        if '_thingy_class_registry' in cls.__dict__:
            return type.__init__(cls, classname, bases, dict_)
        
        cls._thingy_class_registry[classname] = cls
        our_stuff = {}
        for k in dict_:
            value = dict_[k]
            if not isinstance(value, (Column, MapperProperty, declared_synonym)):
                continue
            if isinstance(value, declared_synonym):
                value._setup(cls, k, our_stuff)
            else:
                prop = cls.__deferred_relation(value)
                our_stuff[k] = prop
        
        table = None
        if '__table__' not in cls.__dict__:
            if '__tablename__' in cls.__dict__:
                tablename = cls.__tablename__
                cls.__table__ = table = Table(tablename, cls.metadata, *[
                    c for c in our_stuff.values() if isinstance(c, Column)
                ])
        else:
            table = cls.__table__
        
        inherits = cls.__mro__[1]
        inherits = cls._thingy_class_registry.get(inherits.__name__, None)
        mapper_args = getattr(cls, '__mapper_args__', {})
        
        cls.mapper = mapper(cls, cls.__table__, inherits=inherits, properties=our_stuff, **mapper_args)
        return type.__init__(cls, classname, bases, dict_)
    
    def __deferred_relation(cls, prop):
        if isinstance(prop, PropertyLoader) and isinstance(prop.argument, basestring):
            arg = prop.argument
            def return_cls():
                return cls._thingy_class_registry[arg]
            prop.argument = return_cls
            
        return prop
        
    def __setattr__(cls, key, value):
        if hasattr(cls, 'mapper'):
            if isinstance(value, Column):
                cls.__table__.append_column(value)
                cls.mapper.add_property(key, value)
            elif isinstance(value, MapperProperty):
                cls.mapper.add_property(key, cls.__deferred_relation(value))
            elif isinstance(value, declared_synonym):
                value._setup(cls, key, None)
            else:
                type.__setattr__(cls, key, value)
        else:
            type.__setattr__(cls, key, value)

class declared_synonym(object):
    def __init__(self, prop, name, mapperprop):
        self.prop = prop
        self.name = name
        self.mapperprop = mapperprop
        
    def _setup(self, cls, key, init_dict):
        prop = self.mapperprop
        prop = cls._Thingy__deferred_relation(prop)
        if init_dict:
            init_dict[self.name] = prop
            init_dict[key] = _orm_synonym(self.name)
        else:
            setattr(cls, self.name, prop)
            setattr(cls, key, _orm_synonym(self.name))
        setattr(cls, key, self.prop)
        
        
def declarative_base(engine=None, metadata=None):
    lcl_metadata = metadata or MetaData()
    class Base(object):
        __metaclass__ = Thingy
        metadata = lcl_metadata
        if engine:
            metadata.bind = engine
        _thingy_class_registry = {}
        def __init__(self, **kwargs):
            for k in kwargs:
                setattr(self, k, kwargs[k])
    return Base

if __name__ == '__main__':
    from sqlalchemy import *
    from sqlalchemy.orm import *

    Base = declarative_base(create_engine('sqlite://', echo=True))
    
    class User(Base):
        __tablename__ = 'users'
    
        id = Column('id', Integer, primary_key=True)
        name = Column('name', String(50))
        addresses = relation("Address", backref="user")
        type = Column('type', String(50))
        
        __mapper_args__ = dict(polymorphic_on=type, polymorphic_identity='user')

    class AdminUser(User):
        __tablename__ = 'admin_users'
        __mapper_args__ = dict(polymorphic_identity='adminuser')

        id = Column('id', Integer, ForeignKey('users.id'), primary_key=True)
        supername = Column('supername', String(50))
        
    class Address(Base):
        __tablename__ = 'addresses'

        id = Column('id', Integer, primary_key=True)
        user_id = Column('user_id', Integer, ForeignKey('users.id'))

        def _set_email(self, email):
            self._email = email
        def _get_email(self):
            return self._email
        email = property(_get_email, _set_email)
        email = declared_synonym(email, '_email', Column('email', String(50)))
        
    class Keyword(Base):
        __tablename__ = 'keywords'
        
        id = Column('id', Integer, primary_key=True)
        name = Column('name', String(50))
    
    user_keywords = Table('user_keywords', Base.metadata, 
        Column('user_id', Integer, ForeignKey('users.id')), 
        Column('keyword_id', Integer, ForeignKey('keywords.id'))
    )
    
    # test adding relations after the fact
    User.keywords = relation(Keyword, secondary=user_keywords, backref='users')
        
    Base.metadata.create_all()

    sess = create_session()

    u1 = User(name='ed', 
        addresses=[Address(email='eds email')],
        keywords = [Keyword(name='one'), Keyword(name='two')]
        )

    sess.save(u1)

    a1 = AdminUser(name='some admin', supername='root')
    sess.save(a1)

    sess.flush()
    
    print sess.query(User).filter(User.name=='ed').all()
    print sess.query(User).filter(User.addresses.any(Address.email.like('%ed%'))).all()
    
    print sess.query(User).with_polymorphic('*').all()