OK,

after a long day of experimentation ... I found a solution. This is
the new code (compare to old copied in above):

------------------------------------------------------------------------------------------

class tablemeta(DeclarativeMeta):

    def __new__(mcls, typedef):
        return DeclarativeMeta.__new__(mcls, str(typedef.name),
(BaseTable,Base), {})
    def __init__(cls, typedef):
        reg[cls.__name__] = cls
        cls.links = linkmeta(typedef)
        DeclarativeMeta.__init__(cls, typedef.name, (BaseTable,Base),
{}) #<== FIRST
        members = typedef.all()
        cls.__setlinks(members) #<== ADD RELATIONSHIPS

    def __setlinks(cls, members):
        for mem in members:
            setattr(cls, "_" + mem.name, relationship(cls.links,
                                                    uselist =
(mem.multiplicity != "one"),
                                                    backref =
mem.name,
                                                    primaryjoin =
and_(cls.links.parent_id == cls.id,
 
cls.links.member_name == mem.name)))
-----------------------------------------------------------------------------------------------------------------
The problem seemed to be in the order of adding relationships. The
main difference is that now i call DeclarativeMeta.__init__ before
adding relationships. Even using a dict with relationship attributes
as last argument to __init__ did not work.( BTW cls.links is a table/
class used for references to records in dynamic other tables.)

Hope this helps someone in the future; the error messages can be very
confusing.

On Apr 2, 2:59 pm, farcat <gemer...@gmail.com> wrote:
> Hello,
>
> I get the following error:
> _______________________________________
> Traceback (most recent call last):
>   File "D:\Documents\Code\Eclipse\workspace\SQLAtest\data.py", line
> 29, in <module>
>     I1 = reg["integer"](integer = 5321)
>   File "<string>", line 4, in __init__
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\state.py", line
> 100, in initialize_instance
>     fn(self, instance, args, kwargs)
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\mapper.py", line
> 2413, in _event_on_init
>     instrumenting_mapper.compile()
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\mapper.py", line
> 807, in compile
>     mapper._post_configure_properties()
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\mapper.py", line
> 837, in _post_configure_properties
>     prop.init()
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\interfaces.py",
> line 475, in init
>     self.do_init()
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\properties.py",
> line 900, in do_init
>     self._determine_synchronize_pairs()
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\properties.py",
> line 1157, in _determine_synchronize_pairs
>     eq_pairs = self._sync_pairs_from_join(self.primaryjoin, True)
>   File "C:\python27\lib\site-packages\sqlalchemy\orm\properties.py",
> line 1141, in _sync_pairs_from_join
>     self
> sqlalchemy.exc.ArgumentError: Could not determine relationship
> direction for primaryjoin condition 'False AND False', on relationship
> F_Address_links.number. Ensure that the referencing Column objects
> have a ForeignKey present, or are otherwise part of a
> ForeignKeyConstraint on their parent Table, or specify the
> foreign_keys parameter to this relationship.
> ____________________________________________
>
> Strange thing is that the line  "I1 = reg["integer"](integer = 5321)"
> is the first object/record I create and it works when I do not create
> any other classes. Also the class/table "F_Address_links" in the error
> message exists but no objects/records have been created yet. For
> example I do not understand how "I1 = reg["integer"](integer = 5321)"
> leads to a call to a method that does anything with "F_Address_links"
> or related class/table "F_Address".
>
> Please help ... It might be related to the ForeignKey in the code I
> showed earlier in this thread, but I don't see how.
>
> On Apr 2, 11:56 am, farcat <gemer...@gmail.com> wrote:
>
>
>
>
>
>
>
> > He Michael,
>
> > You saved me again .. Thanks!
>
> > On Apr 2, 2:09 am, Michael Bayer <mike...@zzzcomputing.com> wrote:
>
> > > On Apr 1, 2011, at 2:52 PM, farcat wrote:
>
> > > > Hi Michael,
>
> > > > Still stuck, I don't mixin foreign keys or relationships. When is a
> > > > Column attached to a table in declarative?
>
> > > so you have a few things like:
>
> > > > class AtomBase(BaseBase):
> > > >    id =  Column(Integer, primary_key=True)
>
> > > where AtomBase does not appear to be a declarative class.  Its hard to 
> > > follow but it appears AtomBase is taking the path that mixins take in 
> > > declarative (indeed: "__new__(mcls, name, (AtomBase, Base)").  This means 
> > > "id" will be copied for each actual declarative class generated from 
> > > AtomBase.
>
> > > Later you have:
>
> > > > ForeignKey(parent.id),
>
> > > This is referencing an "id" column probably too early.   In all 
> > > likelihood It isn't being linked to a table, a copy of it is.   Use 
> > > ForeignKey("parent_table_name.id") instead so that the column is 
> > > evaluated as late as possible.
>
> > > > My code is:
>
> > > > import datetime
> > > > from datatypes import *
> > > > from accessors import member_accessor, reference_accessor
>
> > > > from sqlalchemy import *
> > > > from sqlalchemy.orm import relationship
> > > > from sqlalchemy.orm.session import sessionmaker
> > > > from sqlalchemy.ext.declarative import declared_attr, DeclarativeMeta
> > > > from sqlalchemy.types import Text, BigInteger, Float, Boolean, Date,
> > > > Time
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > engine = create_engine('sqlite:///:memory:', echo=False)
> > > > Session = sessionmaker(bind=engine)
> > > > register = dict()
>
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > class BaseBase(object):
> > > >    session = Session()
> > > >    @declared_attr
> > > >    def __tablename__(cls): return cls.__name__
> > > >    def __init__(self, **kwargs):
> > > >        Base.__init__(self, **kwargs)
> > > >        self.session.add(self)
> > > >        print str(self) + " added to session " + str(self.session)
> > > >    def __repr__(self):
> > > >        out = "type: " + type(self).__name__ + "{"
> > > >        for name, mem in self.__dict__:
> > > >            out += name + ": " + str(mem) + ", "
> > > >        out += "}"
> > > >        return out
>
> > > > #--------------------------------------------------------------------
> > > > class AtomBase(BaseBase):
> > > >    id =  Column(Integer, primary_key=True)
> > > >    atomic = True
> > > > #--------------------------------------------------------------------
> > > > class atommeta(DeclarativeMeta):
> > > >    def __new__(mcls, name, coltype):
> > > >        return DeclarativeMeta.__new__(mcls, name, (AtomBase, Base),
> > > > {name:Column(coltype, nullable = False)})
> > > >    def __init__(cls, name, coltype):
> > > >        register[name] = cls
> > > >        return DeclarativeMeta.__init__(cls, name, (AtomBase, Base),
> > > > {})
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > class BaseLink(BaseBase):
>
> > > >    member_name = Column(String(64), primary_key = True) #Name of
> > > > member of parent class
> > > >    member_table = Column(String(64), primary_key = True)  #Name of
> > > > table in which value of member resides
> > > >    member_id = Column(Integer, primary_key = True)          #record
> > > > is in member_table, with previous column enables polymorphism
> > > >    def _getitem(self):
> > > >        t = register[self.member_table]
> > > >        return self.session.query(t).filter(self.member_id ==
> > > > t.id).one()
> > > >    def _setitem(self, val):
> > > >        try: del self.item
> > > >        except AttributeError:   pass
> > > >        self.member_table = val.__tablename__
> > > >        self.member_id = val.id
> > > >    def _delitem(self):
> > > >        t = register[self.member_table]
> > > >        self.session.query(t).filter(t.id == self.member_id).delete()
> > > >    item = property(_getitem, _setitem, _delitem)
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > class BaseTable(BaseBase):
>
> > > >    id = Column(Integer, primary_key = True)
> > > >    created_at = Column(DateTime, default=datetime.datetime.now())
> > > >    atomic = False
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > class linkmeta(DeclarativeMeta):
> > > >    def __new__(mcls, parent):
> > > >        return DeclarativeMeta.__new__(mcls, "%s_links" %
> > > > parent.__name__, (BaseLink, Base),
> > > >                                       {"parent_id": Column(Integer,
> > > > ForeignKey(parent.id), primary_key=True)})
> > > >    def __init__(cls, parent):
> > > >        return DeclarativeMeta.__init__(cls, "%s_links" %
> > > > parent.__name__, (BaseLink, Base), {})
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > class tablemeta(DeclarativeMeta):
>
> > > >    def __new__(mcls, typedef):
> > > >        out = DeclarativeMeta.__new__(mcls, str(typedef.name),
> > > > (BaseTable,Base), {})
> > > >        out.links = linkmeta(out) #<== Creates class/table enables
> > > > links to other tables
> > > >        members = typedef.all()
> > > >        for mem in members:
> > > >            if not mem.type.name in register:
> > > >                tablemeta(mem.type)
> > > >            setattr(out, "_" + mem.name, relationship(out.links,
> > > >                                                    uselist =
> > > > (mem.multiplicity != "one"),
> > > >                                                    backref =
> > > > mem.name,
> > > >                                                    primaryjoin =
> > > > and_(out.links.parent_id == out.id,
>
> > > > out.links.member_name == mem.name)))
> > > >        return out
> > > >    def __init__(cls, typedef):
> > > >        register[cls.__name__] = cls
> > > >        temp = dict()
> > > >        members = typedef.all()
> > > >        for mem in members:
> > > >            if mem.reference:
> > > >                temp[mem.name] = reference_accessor(mem.name,
> > > > register[mem.type_name], mem.multiplicity)
> > > >            else:
> > > >                temp[mem.name] = member_accessor(mem.name,
> > > > register[mem.type_name], mem.multiplicity)
> > > >        return DeclarativeMeta.__init__(cls, typedef.name,
> > > > (BaseTable,Base), temp)
> > > > #--------------------------------------------------------------------------
> > > >  -
> > > > def createClasses(engine, session):
> > > >    print "creating classes and tables"
> > > >    atommeta("text", Text)
> > > >    atommeta("integer", BigInteger)
> > > >    atommeta("decimal", Float)
> > > >    atommeta("boolean", Boolean)
> > > >    atommeta("date", Date)
> > > >    atommeta("time", Time)
> > > >    typedefs = session.query(Type).filter(Type.atomic == False).all()
> > > >    for typedef in typedefs:
> > > >        tablemeta(typedef)
> > > >    print
> > > > "--------------------------------------------------------------------------
> > > >  ---------"
> > > >    for reg in register:
> > > >        print reg
> > > >    Base.metadata.create_all(engine) #<== ERROR
> > > >    print"done"
>
> ...
>
> read more »

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@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