2013-02-14 1 views
9

Ich habe eine übergeordnete Tabelle namens pbx_point, die eine point_type Spalte hat. Ich habe auch eine Kind-Tabelle namens pbx_route, mit einer Spalte namens point_id, die zurück zu pbx_point zeigt.Wie kann ich in sqlalchemy die Vererbung von verknüpften Tabellen polymorph verwenden, wenn die untergeordnete Tabelle mehrere Fremdschlüssel für die übergeordnete Tabelle enthält?

Ich möchte sqlalchemy der verknüpften Tabelle Vererbung verwenden diese beiden Tabellen über deklarative Basis zu beziehen und verwenden polymorphe Erbe

Dies funktioniert gut - oder besser gesagt, es wäre, wenn nicht für die folgende zusätzliche Einschränkung: pbx_point hat auch einen Fremdschlüssel namens initial_route_id, der auf pbx_route zeigt.

Ich benutze auch Reflexion unten, aber die db ist wie ich oben beschrieben. Der Fehler, den ich bekomme, ist sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'pbx_point' and 'pbx_route'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly..

Dies ist sinnvoll, da delkarative Basis "hinter den Kulissen" ein Attribut relation() auf beiden zugeordneten Klassen erstellt. Ich möchte, dass es pbx_route.point_id als den Link parent_id wählt, aber es sieht auch die Spalte pbx_point.initial_route_id. Dies wäre einfach zu beheben, wenn ich diese Beziehung() erstellen würde, aber ich bin nicht - das deklarative Vererbung System ist.

Gibt es ein zusätzliches Argument, das ich an __mapper_args__ weiterleiten kann, wie zum Beispiel polymorphic_parent_col, mit dem ich den gewünschten Fremdschlüssel angeben könnte? Wenn nicht, wie kann ich dieses Problem umgehen?

Danke.

class MyBase(DeferredReflection): 
    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

Base = declarative_base(cls=MyBase) 

class pbx_point(Base): 
    __mapper_args__ = dict(
     polymorphic_on='point_type', 
     with_polymorphic='*', 
    ) 

class pbx_route(pbx_point): 
    __mapper_args__ = dict(polymorphic_identity='pbx.route') 

Dies ist der Stack-Trace Ich erhalte:

Traceback (most recent call last): 
    File "db.py", line 50, in <module> 
    Base.prepare(engine) 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 431, in prepare 
    thingy.map() 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 379, in map 
    **mapper_args 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/__init__.py", line 1147, in mapper 
    return Mapper(class_, local_table, *args, **params) 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 213, in __init__ 
    self._configure_inheritance() 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 517, in _configure_inheritance 
    self.local_table) 
    File "env/local/lib/python2.7/site-packages/sqlalchemy/sql/util.py", line 397, in join_condition 
    "join explicitly." % (a.description, b.description)) 
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'pbx_point' and 'pbx_route'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly. 

Was es bei https://bitbucket.org/sqlalchemy/sqlalchemy/src/7f3494ebad58/lib/sqlalchemy/orm/mapper.py?at=default#cl-517 stirbt an. Ein paar Zeilen darüber sagt der Mapper Kwarg inherit_condition, die scheint, was ich brauche.

Antwort

10

Der Schlüssel ist das inherit_condition Argument für den Mapper. Die polymorphe Information hat mit diesem Schritt eigentlich nichts zu tun.

Korrigierte Modelle:

class MyBase(DeferredReflection): 
    @declared_attr 
    def __tablename__(cls): 
     return cls.__name__.lower() 

Base = declarative_base(cls=MyBase) 

class pbx_point(Base): 
    __mapper_args__ = dict(
     polymorphic_on='point_type', 
     with_polymorphic='*', 
    ) 
    id = Column(Integer, primary_key=True) 

class pbx_route(pbx_point): 
    point_id = Column(Integer, ForeignKey(pbx_point.id)) 
    __mapper_args__ = dict(
     polymorphic_identity='pbx.route', 
     inherit_condition=(point_id == pbx_point.id) 
    ) 

Ich brauchte die id und point_id Spalten hinzufügen sie in der inherit_condition Argument zu verwenden. Es gibt wahrscheinlich einen Weg, dies nur durch Reflexion zu tun, aber das ist kein schreckliches Hindernis.

+1

Ich hatte dieses genaue Problem und konnte es nicht in der Dokumentation finden. Danke für die Antwort. –