Подтвердить что ты не робот

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

Я немного запутался в наследовании по 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 жителя?

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

Решение 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')

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