2013-02-14 5 views
9

Ho una tabella padre denominata pbx_point che ha una colonna point_type. Ho anche un tavolo per bambini chiamato pbx_route, con una colonna chiamata point_id che punta a pbx_point.In sqlalchemy, come posso utilizzare l'ereditarietà della tabella unita polimorfa quando la tabella figlio ha più chiavi esterne alla tabella padre?

mi piacerebbe utilizzare l'ereditarietà tabella unita del sqlalchemy mettere in relazione queste due tabelle via di base dichiarativa, e utilizzare l'ereditarietà polimorfico

Questo funziona bene - o meglio, sarebbe, se non fosse per il seguente vincolo aggiuntivo: pbx_point ha anche una chiave esterna chiamata initial_route_id che punta a pbx_route.

Sto anche utilizzando la riflessione in basso, ma il db è come descritto sopra. L'errore che ottengo è 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..

Questo ha senso, poiché la base delcarativa "dietro le quinte" crea un attributo relationship() su entrambe le classi mappate. Mi piacerebbe scegliere pbx_route.point_id come link parent_id, ma anche la colonna pbx_point.initial_route_id. Questo sarebbe semplice da risolvere, se stavo creando questa relazione(), ma non lo sono - il sistema di ereditarietà dichiarativa è.

C'è un argomento aggiuntivo che posso passare a __mapper_args__, ad esempio polymorphic_parent_col che mi consente di specificare la chiave esterna che desidero? In caso contrario, come posso risolvere questo problema?

Grazie.

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

Questa è l'analisi dello stack sto ottenendo:

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. 

che indica che sta morendo a https://bitbucket.org/sqlalchemy/sqlalchemy/src/7f3494ebad58/lib/sqlalchemy/orm/mapper.py?at=default#cl-517. Alcune righe sopra fanno riferimento al mapper kwarg inherit_condition, che sembra essere quello di cui ho bisogno.

risposta

10

La chiave è l'argomento inherit_condition per il mapping. Le informazioni polimorfiche in realtà non hanno nulla a che fare con questo passaggio.

modelli corretti:

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

avevo bisogno di aggiungere le id e point_id colonne di usarli nell'argomento inherit_condition. È probabile che ci sia un modo per farlo usando solo la riflessione, ma questo non è un ostacolo terribile.

+1

Ho avuto questo problema esatto e NON sono riuscito a trovarlo nei documenti. Grazie per la risposta. –

Problemi correlati