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

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

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)

Антс Аасма 'Решение гораздо более элегантное, но если вы намеренно храните определения классов отдельно от определений таблиц, вам необходимо отобразить ваши классы на таблицы с помощью функции 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')

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

Решение Вопроса

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

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

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() метод.

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

 Lyman Zerga04 мая 2016 г., 20:41
Это может быть глупый вопрос, но как выглядят базовые таблицы SQL в наследовании одной таблицы? Есть только 1building Таблица SQL, которая включает в себяbusiness а такжеnum_residents колонны?
 ThatAintWorking15 апр. 2015 г., 19:47
Единственное, чего не хватает - это пример использования конкретного наследования таблиц - тот, с которым я, естественно, обращаюсь за помощью :-) Поскольку это старый вопрос, возможно, после ответа на этот вопрос было добавлено наследование конкретных таблиц.
 Sasha Chedygov05 июн. 2016 г., 23:43
@ LymanZerga: Да, именно так это выглядит в БД. Он создает все столбцы в одной таблице и просто создает правильную модель в Python на основе значения поля, на которое ссылается.polymorphic_on
 Philipp der Rautenberg06 дек. 2011 г., 09:10
Для более конкретной проблемы, связанной с наследованием объединенной таблицы, см.stackoverflow.com/questions/8389606/...
 Noah27 авг. 2009 г., 17:02
Вау, это отличный ответ. Спасибо! Так что я'Вы сравнили производительность между параметрами одиночной и объединенной таблиц и обнаружили, что второй запрос [filter (Residential.num_residents == n) .count ()] выполняется в 2 раза быстрее в сценарии с одной таблицей (как и ожидалось). Однако по какой-то причине первый запрос к Building [filter ((Building.x> Икс) & (Building.y> y)). count ()] примерно на 10% медленнее с одной таблицей, хотя загрузка всех элементов фактически сопоставима (.all ()).

Ваш ответ на вопрос