Hello world!

I am currently trying to transform my code from classic (schema defined
in an extra python module) to declarative. As intermediate step I am
moving the table definitions to the class implementations.

What I am running into is sketched in the following example. In reality,
I have different modules for Base, Derived and Owner.


-------
from sqlalchemy import *
from sqlalchemy.orm import *

metadata = MetaData()

class Base(object): pass

base_table = Table("base", metadata,
    Column("id", Integer, primary_key=True),
    Column("target_type", String))

mapper(Base, base_table, polymorphic_on=base_table.c.target_type)


class Derived(Base): pass

derived_table = Table("derived", metadata,
    Column("id", Integer, ForeignKey("base.id"), primary_key=True),
    Column("owner_id", Integer, ForeignKey("owner.owner_id"), nullable=False))

mapper(Derived, derived_table, polymorphic_identity="derived", inherits=Base)


class Owner(object): pass

owner_table = Table("owner", metadata,
    Column("owner_id", Integer, primary_key=True))

mapper(Owner, owner_table)
-------


Running this gives me the following exception:


Traceback (most recent call last):
  File "inherit_problem.py", line 21, in <module>
    mapper(Derived, derived_table, polymorphic_identity="derived", 
inherits=Base)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/orm/__init__.py",
 line 890, in mapper
    return Mapper(class_, local_table, *args, **params)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/orm/mapper.py",
 line 208, in __init__
    self._configure_inheritance()
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/orm/mapper.py",
 line 259, in _configure_inheritance
    self.local_table)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/sql/util.py",
 line 227, in join_condition
    col = fk.get_referent(left)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/schema.py",
 line 1161, in get_referent
    return table.corresponding_column(self.column)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/util.py",
 line 1517, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File 
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.8dev-py2.6.egg/sqlalchemy/schema.py",
 line 1223, in column
    "foreign key to target column '%s'" % (self.parent, tname, colname))
sqlalchemy.exc.NoReferencedTableError: Foreign key assocated with column 
'derived.owner_id' could not find table 'owner' with which to generate a 
foreign key to target column 'owner_id'


The solution is of course to define all the tables first and do the
mapping only after that. This would put me back to point one.


I tried to get around this by patching SA with this patch:


-------
diff -r 27fec7a0e05f lib/sqlalchemy/orm/mapper.py
--- a/lib/sqlalchemy/orm/mapper.py      Wed Apr 27 12:51:50 2011 -0400
+++ b/lib/sqlalchemy/orm/mapper.py      Thu Apr 28 16:26:57 2011 +0200
@@ -256,7 +256,8 @@
                         # want (allows test/inheritance.InheritTest4 to pass)
                         self.inherit_condition = sqlutil.join_condition(
                                                     self.inherits.local_table,
-                                                    self.local_table)
+                                                    self.local_table,
+                                                    
ignore_nonexistent_tables=True)
                     self.mapped_table = sql.join(
                                                 self.inherits.mapped_table, 
                                                 self.local_table,
-------


This makes the example work, but I'd rather stay with an official
SQLAlchemy. So would it be possible to make this work out of the box? Is
there a better way to implement this?

Any hints are greatly appreciated.

Torsten

PS: I just tried to implement this in a declarative way. This seems to
work fine:


-------
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

DeclBase = declarative_base()

class Base(DeclBase):
    __tablename__ = "base"
    id = Column(Integer, primary_key=True)
    target_type = Column(String)

    __mapper_args__ = { "polymorphic_on": target_type }


class Derived(Base):
    __tablename__ = "derived"
    id = Column(Integer, ForeignKey(Base.id), primary_key=True)
    owner_id = Column(Integer, ForeignKey("owner.owner_id"), nullable=False)
    owner = relationship("Owner")

    __mapper_args__ = { "polymorphic_identity": "derived" }


class Owner(DeclBase):
    __tablename__ = "owner"
    owner_id = Column(Integer, primary_key=True)

engine = create_engine("sqlite:///:memory:", echo=True)
DeclBase.metadata.create_all(engine)
session = sessionmaker(engine)()

owner = Owner()
derived = Derived(owner=owner)
session.add(derived)
session.commit()
-------

However, I already failed to do the whole conversion in one giant commit, 
therefore I would prefer to do it in small steps.


-- 
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff

Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561

mailto:torsten.landsch...@dynamore.de
http://www.dynamore.de

Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director:  Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz

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