Hi,

Using plain Declarative, I am able to redefine a primary key column
that has been autoloaded, so that I can link it to an oracle sequence
and give it a new name:

Id = Column('id', Integer, Sequence('table_sq'), primary_key=True)


However, if I then try to add some methods to the class using a
metaclass, the foreign key relationships pointing to this column, seem
to go missing.

Apologies for not being able to track down the exact cause of this,
but it seems to be something I am doing wrong with the combination of
autloading, redefining the primary key, and adding to the class
through a metaclass.

The following example should work against an empty oracle schema.


I get: "sqlalchemy.exc.ArgumentError: Could not determine join
condition between parent/child tables on relationship
Customer.addresses.  Specify a 'primaryjoin' expression.  If this is a
many-to-many relationship, 'secondaryjoin' is needed as well."


http://python.pastebin.com/7V8MEfH3


from sqlalchemy import MetaData, Column, Integer, Sequence,
ForeignKey, create_engine
from sqlalchemy.orm import relationship, sessionmaker, scoped_session
from sqlalchemy.ext.declarative import DeclarativeMeta,
declarative_base

engine = create_engine('oracle://fred:f...@mig01')

ddls = [
    """drop table customer""",
    """drop table address""",
    """drop table country""",
    """drop table customer_type""",
    """create table customer_type (
        id number primary key,
        name varchar2(10))""",
    """create table country (
        id number primary key,
        name varchar2(10))""",
    """create table customer (
        id number primary key,
        name varchar2(10),
        customer_type_id number references customer_type)""",
    """create table address (
        id number primary key,
        name varchar2(10),
        country_id number references country,
        customer_id number references customer)""",
]

for ddl in ddls:
    try:
        print ddl,
        engine.execute(ddl)
        print 'ok'

    except:
        print 'fail'
        pass


metadata = MetaData(bind=engine)

Session = scoped_session(sessionmaker())


class RelationNameAttribute(object):

    def __init__(self, relationname, childclass):
        self.relationname = relationname
        self.query = Session.query(childclass)

    def __get__(self, obj, objtype):
        return getattr(getattr(obj, self.relationname), 'name')

    def __set__(self, obj, val):
        child = self.query.filter_by(name=val).one()
        setattr(obj, self.relationname, child)


class DataMeta(DeclarativeMeta):

    def __init__(cls, classname, bases, dict_):

        classvalues = {}

        for name, obj in vars(cls).items():

            #print name
            if name in ('entity',
                        'entity_id',
                        'event_id',
                        'attributes',
                        '__tablename__',
                        'history_table',
                        'id_column',
                        'relations'):

                classvalues[name] = obj


        if 'attributes' in classvalues:   # could have checked for any
variable names

            #
            # Id attribute
            #

            sequence_name = classvalues['__tablename__'] + '_sq'


            cls.Id = Column('id', Integer, Sequence(sequence_name),
primary_key=True)


            #
            # Other attributes
            #

            for aname, nname, rname, childclass in
classvalues['attributes']:



                #
                # A relationship attribute
                #


                # The relationship

                setattr(cls, rname, relationship(childclass,
uselist=False))

                # The Name attribute

                setattr(cls, nname, RelationNameAttribute(rname,
childclass))

            #
            # Table arguments
            #

            cls.__table_args__ = {'autoload'    : True,
                                  'useexisting' : True}



        return DeclarativeMeta.__init__(cls, classname, bases, dict_)





BaseForConfig = declarative_base(metadata=metadata)
BaseForData = declarative_base(metaclass=DataMeta,  metadata=metadata)



class Country(BaseForConfig):
    __tablename__  = 'country'
    __table_args__ = {'autoload' : True}

class CustomerType(BaseForConfig):
    __tablename__  = 'customer_type'
    __table_args__ = {'autoload' : True}


class Address(BaseForData):
    __tablename__  = 'address'
    history_table  = 'address_history'
    id_column      = 'addrnr'

    entity         = 'Address'
    entity_id      = 2
    event_id       = 103


    attributes = [
        ('CountryKey', 'CountryName', 'country', Country),
    ]


class Customer(BaseForData):
    __tablename__ = 'customer'


    attributes = [
        ('TypeKey', 'TypeName', 'type', CustomerType)
    ]


    addresses = relationship( Address, backref='customer')


c = Customer()
print dir(c)
print c.addresses


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