Наследование SQLAlchemy - PullRequest
       18

Наследование SQLAlchemy

47 голосов
/ 26 августа 2009

Я немного озадачен наследованием в sqlalchemy, до такой степени, что я даже не уверен, какой тип наследования (отдельная таблица, объединенная таблица, конкретный) мне следует использовать здесь У меня есть базовый класс с некоторой информацией, которая распределяется между подклассами, и некоторыми данными, которые полностью разделены. Иногда мне нужны данные из всех классов, а иногда только из подклассов. Вот пример:

class Building:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Commercial(Building):
    def __init__(self, x, y, business):
        Building.__init__(self, x, y)
        self.business = business

class Residential(Building):
    def __init__(self, x, y, numResidents):
        Building.__init__(self, x, y, layer)
        self.numResidents = numResidents

Как бы я преобразовал это в SQLAlchemy с помощью декларативного? Как тогда я могу узнать, какие здания находятся в пределах x>5 и y>3? Или какие жилые дома имеют только 1 житель?

Ответы [ 2 ]

80 голосов
/ 27 августа 2009

Выбор способа представления наследования в основном является проблемой проектирования базы данных. Для производительности наследование одной таблицы обычно лучше. С точки зрения хорошего дизайна базы данных, наследование объединенной таблицы лучше. Наследование объединенных таблиц позволяет вам иметь внешние ключи для подклассов, применяемые базой данных, намного проще иметь ненулевые ограничения для полей подкласса. Наследование бетонных таблиц является худшим из обоих миров.

Настройка наследования одной таблицы с декларативным выглядит следующим образом:

class Building(Base):
    __tablename__ = 'building'
    id = Column(Integer, primary_key=True)
    building_type = Column(String(32), nullable=False)
    x = Column(Float, nullable=False)
    y = Column(Float, nullable=False)
    __mapper_args__ = {'polymorphic_on': building_type}

class Commercial(Building):
    __mapper_args__ = {'polymorphic_identity': 'commercial'}
    business = Column(String(50))

class Residential(Building):
    __mapper_args__ = {'polymorphic_identity': 'residential'}
    num_residents = Column(Integer)

Чтобы сделать это наследованием объединенной таблицы, вам нужно добавить

__tablename__ = 'commercial'
id = Column(None, ForeignKey('building.id'), primary_key=True)

к подклассам.

Запросы в большинстве случаев одинаковы для обоих подходов:

# buildings that are within x>5 and y>3
session.query(Building).filter((Building.x > 5) & (Building.y > 3))
# Residential buildings that have only 1 resident
session.query(Residential).filter(Residential.num_residents == 1)

Для контроля загружаемых полей вы можете использовать метод query.with_polymorphic().

Самая важная вещь, которую стоит подумать об использовании наследования для отображения данных, заключается в том, действительно ли вам нужно наследование или вы можете делать с агрегацией. Наследование будет болезненным, если вам когда-нибудь потребуется изменить тип здания, или ваши здания могут иметь как коммерческие, так и жилые аспекты. В этих случаях обычно лучше иметь коммерческие и жилые аспекты в качестве связанных объектов.

11 голосов
/ 27 августа 2009

Решение Ants Aasma гораздо более элегантно, но если вы намеренно держите определения классов отдельно от определений таблиц, вам необходимо отобразить ваши классы на таблицы с помощью функции mapper. После того, как вы определили свои классы, вам нужно определить свои таблицы:

building = Table('building', metadata,
    Column('id', Integer, primary_key=True),
    Column('x', Integer),
    Column('y', Integer),
)
commercial = Table('commercial', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('business', String(50)),
)
residential = Table('residential', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('numResidents', Integer),
)

Затем вы можете сопоставить таблицы с классами:

mapper(Building, building)
mapper(Commercial, commercial, inherits=Building, polymorphic_identity='commercial')
mapper(Residential, residential, inherits=Building, polymorphic_identity='residential')

Затем взаимодействуйте с классами точно так же, как описал Муравей Аасма.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...