2013-02-14 19 views
9

Mam tabelę nadrzędną o nazwie pbx_point, która ma kolumnę point_type. Mam także tabelę podrzędną o nazwie pbx_route, z kolumną o nazwie point_id, która wskazuje na pbx_point.W sqlalchemy, w jaki sposób mogę użyć polimorficznego połączonego dziedziczenia tabel, gdy tabela podrzędna ma wiele kluczy obcych do tabeli nadrzędnej?

Chciałbym użyć sqlalchemy dołączył tabeli dziedziczenie powiązać te dwie tabele poprzez deklaratywnej podstawy i używać polimorficzny dziedziczenie

Działa to dobrze - albo raczej, że będzie, jeśli nie na następujące dodatkowe ograniczenia: pbx_point ma również klucz obcy o nazwie initial_route_id wskazujący na pbx_route.

Używam także odbicie poniżej, ale db jest jak opisano powyżej. Błąd, który dostaję, to 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..

To ma sens, ponieważ podstawą delkaratywną "za kulisami" jest tworzenie atrybutu relationship() na obu zamapowanych klasach. Chciałbym wybrać pbx_route.point_id jako link parent_id, ale widzi również kolumnę pbx_point.initial_route_id. Byłoby to łatwe do naprawienia, jeśli tworzyłem ten związek(), ale nie jestem - deklaratywny system dziedziczenia jest.

Czy istnieje dodatkowy argument, który można przekazać do __mapper_args__, na przykład polymorphic_parent_col, który pozwoli mi określić klucz zagraniczny, którego pragnę? Jeśli nie, jak mogę obejść ten problem?

Dzięki.

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

To jest ślad stosu Dostaję:

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. 

Który wskazuje, że umiera na https://bitbucket.org/sqlalchemy/sqlalchemy/src/7f3494ebad58/lib/sqlalchemy/orm/mapper.py?at=default#cl-517. Kilka linijek powyżej sprawia, że ​​odesłanie do kwarca mapowego inherit_condition wydaje się być tym, czego potrzebuję.

Odpowiedz

10

Kluczem jest argument inherit_condition dla programu odwzorowującego. Informacja polimorficzna w rzeczywistości nie ma nic wspólnego z tym krokiem.

Poprawione modele:

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

Musiałem dodać id i point_id kolumny z nich korzystać w inherit_condition argument. Prawdopodobnie można to zrobić tylko za pomocą refleksji, ale nie jest to żadna straszna przeszkoda.

+1

Miałem dokładnie ten problem i NIE mogłem go znaleźć w dokumentach. Dziękuję za odpowiedź. –