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.