SQLAlchemy декларативное наследование конкретных автозагрузочных таблиц
-
06-07-2019 - |
Вопрос
У меня уже есть база данных, и я хочу получить к ней доступ с помощью SQLAlchemy. Потому что структура базы данных управляется другим фрагментом кода (на самом деле Django ORM), и я не хочу повторяться, описывая каждую структуру таблицы, я использую самоанализ autoload
. Я застрял с простым наследованием конкретной таблицы.
Payment FooPayment
+ id (PK) <----FK------+ payment_ptr_id (PK)
+ user_id + foo
+ amount
+ date
Вот код с таблицами SQL в виде строк документации:
class Payment(Base):
"""
CREATE TABLE payments(
id serial NOT NULL,
user_id integer NOT NULL,
amount numeric(11,2) NOT NULL,
date timestamp with time zone NOT NULL,
CONSTRAINT payment_pkey PRIMARY KEY (id),
CONSTRAINT payment_user_id_fkey FOREIGN KEY (user_id)
REFERENCES users (id) MATCH SIMPLE)
"""
__tablename__ = 'payments'
__table_args__ = {'autoload': True}
# user = relation(User)
class FooPayment(Payment):
"""
CREATE TABLE payments_foo(
payment_ptr_id integer NOT NULL,
foo integer NOT NULL,
CONSTRAINT payments_foo_pkey PRIMARY KEY (payment_ptr_id),
CONSTRAINT payments_foo_payment_ptr_id_fkey
FOREIGN KEY (payment_ptr_id)
REFERENCES payments (id) MATCH SIMPLE)
"""
__tablename__ = 'payments_foo'
__table_args__ = {'autoload': True}
__mapper_args__ = {'concrete': True}
В реальных таблицах есть дополнительные столбцы, но это совершенно не имеет отношения к вопросу, поэтому, пытаясь свести к минимуму код, я упростил все до глубины души.
Проблема в том, что когда я запускаю это:
payment = session.query(FooPayment).filter(Payment.amount >= 200.0).first()
print payment.date
Результирующий SQL не имеет смысла (обратите внимание на отсутствие условий соединения):
SELECT payments_foo.payment_ptr_id AS payments_foo_payment_ptr_id,
... /* More `payments_foo' columns and NO columns from `payments' */
FROM payments_foo, payments
WHERE payments.amount >= 200.0 LIMIT 1 OFFSET 0
И когда я пытаюсь получить доступ к payment.date
, я получаю следующую ошибку: Concrete Mapper | FooPayment | payment_foo не реализует атрибут u'date 'на уровне экземпляра. код>
Я попытался добавить неявную ссылку на внешний ключ id = Column ('payment_ptr_id', Integer, ForeignKey ('payment_payment.id'), primary_key = True)
в FooPayment
Безуспешно. Попытка print session.query (Payment) .first (). User
работает (я пропустил класс User
и прокомментировал строку) отлично, так что самоанализ FK работает. р>
Как мне выполнить простой запрос к FooPayment
и получить доступ к значениям Payment
из полученного экземпляра?
Я использую SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 и Python 2.5.2. Спасибо за любые предложения.
Решение
Структуры вашей таблицы аналогичны тем, которые используются в объединенном наследовании таблиц, но они определенно не соответствуют конкретному наследованию таблиц, где все поля родительского класса дублируются в таблице подкласса. Прямо сейчас у вас есть подкласс с меньшим количеством полей, чем у родителя, и ссылка на экземпляр родительского класса. Переключитесь на объединенное наследование таблиц (и используйте FooPayment.amount
в своем состоянии или откажитесь от наследования в пользу простого агрегирования (ссылка).
Фильтр по полю в другой модели не добавляет автоматически условие соединения. Хотя для вашего примера очевидно, какое условие следует использовать в соединении, определить такое условие в целом невозможно. Вот почему вы должны определить свойство отношения со ссылкой на Платеж и использовать его метод has ()
в фильтре, чтобы получить правильное условие соединения.