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 <[email protected]> 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 <[email protected]> wrote:
>
>
>
>
>
>
>
> > He Michael,
>
> > You saved me again .. Thanks!
>
> > On Apr 2, 2:09 am, Michael Bayer <[email protected]> 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 [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.