SQLAlchemy ORM - 3-х объектные отношения - PullRequest
0 голосов
/ 30 января 2020

Я использую SQLAlchemy с Postgres.
Пример кода из https://auth0.com/blog/sqlalchemy-orm-tutorial-for-python-developers/

У меня есть 3 объекта:

  • Актер
  • Stuntman
  • ContactDetails

В исходном примере кода отношения следующие:

  • Актер: ContactDetails = 1: 0 .. *
  • Актер: Stuntman = 1: 1

См. Код:

class Actor(Base):
    __tablename__ = 'actors'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    birthday = Column(Date)


class Stuntman(Base):
    __tablename__ = 'stuntmen'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    active = Column(Boolean)
    actor_id = Column(Integer, ForeignKey('actors.id'))
    actor = relationship("Actor", backref=backref("stuntman", uselist=False))


class ContactDetails(Base):
    __tablename__ = 'contact_details'

    id = Column(Integer, primary_key=True)
    phone_number = Column(String)
    address = Column(String)
    actor_id = Column(Integer, ForeignKey('actors.id'))
    actor = relationship("Actor")

Я пытаюсь расширить эту модель для следующих отношений:

  • Актер: ContactDetails = 1: 0 .. *
  • Актер: Stuntman = 1: 1
  • Stuntman: ContactDetails = 1: 0 .. *

Каскадеры тоже много работают и заслуживают ContactDetails. Кто может помочь, пожалуйста?!

1 Ответ

1 голос
/ 30 января 2020

На мой взгляд, лучший способ достичь того, что вам нужно, это использовать таблицу ассоциаций. Это должно работать:

actors_to_contact_details = Table('actors_to_contact_details', Base.metadata,
    Column('actor_id', Integer, ForeignKey('actors.id')),
    Column('contact_detail_id', Integer, ForeignKey('contact_details.id'))
)


stuntmen_to_contact_details = Table('stuntmen_to_contact_details', Base.metadata,
    Column('stuntman_id', Integer, ForeignKey('stuntmen.id')),
    Column('contact_detail_id', Integer, ForeignKey('contact_details.id'))
)


class Actor(Base):
    __tablename__ = 'actors'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    birthday = Column(Date)
    contact_details = relationship("ContactDetails", secondary=actors_to_contact_details)


class Stuntman(Base):
    __tablename__ = 'stuntmen'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    active = Column(Boolean)
    actor_id = Column(Integer, ForeignKey('actors.id'))
    actor = relationship("Actor", backref=backref("stuntman", uselist=False))
    contact_details = relationship("ContactDetails", backref="stuntman", secondary=stuntmen_to_contact_details)


class ContactDetails(Base):
    __tablename__ = 'contact_details'

    id = Column(Integer, primary_key=True)
    phone_number = Column(String)
    address = Column(String)

, если хотите, вы можете поместить unique=True в таблицу сопоставления, как это

actors_to_contact_details = Table('actors_to_contact_details', Base.metadata,
    Column('actor_id', Integer, ForeignKey('actors.id')),
    Column('contact_detail_id', Integer, ForeignKey('contact_details.id'), unique=True)
)


stuntmen_to_contact_details = Table('stuntmen_to_contact_details', Base.metadata,
    Column('stuntman_id', Integer, ForeignKey('stuntmen.id')),
    Column('contact_detail_id', Integer, ForeignKey('contact_details.id'), unique=True)
)

Другой вариант - поставить еще один обнуляемый внешний ключ на Stuntman таблица, но я бы go с решением, представленным выше.

...