Отображение «поддельного» объекта в SQLAlchemy - PullRequest
2 голосов
/ 12 апреля 2011

Я не уверен, как это называется, так как это ново для меня, но вот что я хочу сделать:

У меня есть две таблицы в моей базе данных: TableA и TableB. TableA имеет pk a_id и другое поле, называемое a_code. TableB имеет pk b_id и другое поле с именем b_code.

У меня есть эти таблицы в моем коде sqlalchemy, и они работают нормально. Я хочу создать третий объект с именем TableC, который фактически не существует в моей базе данных, но который содержит комбинации a_code и b_code, что-то вроде этого:

class TableC:
  a_code = String
  b_code = String

Тогда я бы хотел запросить TableC как:

TableC.query.filter(and_(
        TableC.a_code == x,
        TableC.b_code == y)).all()

Вопрос 1) У этого типа вещей есть имя? 2) Как мне сделать сопоставление (было бы неплохо использовать декларативное)?

Ответы [ 3 ]

6 голосов
/ 08 сентября 2011

У меня нет полного понимания запроса , который вы пытаетесь выразить, если это объединение, объединение или какая-то третья вещь, но, кроме этого, это, безусловно, - это возможно отобразить произвольный выбор (все, что вы можете передать в базу данных, которая возвращает строки).

Я начну с предположения, что вы хотите какое-то объединение таблиц A и Table B, которое будет содержать все строки в A, а также все строки в B. Это достаточно легко изменить на другой Концепция, если вы раскрываете больше информации о форме данных, которые вы выражаете.

Начнем с настройки реальных таблиц и классов для их отображения в декларативном стиле.

from sqlalchemy import *
import sqlalchemy.ext.declarative

Base = sqlalchemy.ext.declarative.declarative_base()

class TableA(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    a_code = Column(String)

class TableB(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    b_code = Column(String)

Так как мы использовали декларативный, у нас фактически нет экземпляров таблиц для работы, что необходимо для следующей части. Есть много способов доступа к таблицам, но я предпочитаю использовать методы самоанализа отображения с помощью sqlalchemy, так как это будет работать независимо от того, как был отображен класс.

from sqlalchemy.orm.attributes import manager_of_class
a_table = manager_of_class(TableA).mapper.mapped_table
b_table = manager_of_class(TableB).mapper.mapped_table

Далее нам нужно фактическое выражение sql, которое представляет интересующие нас данные. Это объединение, в результате столбцы которого выглядят так же, как столбцы, определенные в первом классе, id и a_code. Мы могли бы переименовать его, но это не очень важная часть примера.

ab_view_sel = sqlalchemy.alias(a_table.select().union(b_table.select()))

Наконец, мы сопоставляем класс с этим. Для этого можно использовать декларативное, но на самом деле это больше кода, чем классический стиль отображения, а не меньше. Обратите внимание, что класс наследуется от object, а не base

class ViewAB(object):
    pass

sqlalchemy.orm.mapper(ViewAB, ab_view_sel)

И это во многом. Конечно, есть некоторые ограничения с этим; наиболее очевидно, что нет (тривиального) способа сохранить экземпляры ViewAB обратно в базу данных.

1 голос
/ 08 сентября 2011

Похоже, что SQLAlchemy позволяет сопоставить произвольный запрос с классом.Например, из SQLAlchemy: один класс - две таблицы :

usersaddresses = sql.join(t_users, t_addresses,
                           t_users.c.id == t_addresses.c.user_id)
class UserAddress(object):
    def __repr__(self):
        return "<FullUser(%s,%s,%s)" % (self.id, self.name, self.address)

mapper(UserAddress, usersaddresses, properties={
        'id': [t_users.c.id, t_addresses.c.user_id],
        })

f = session.query(UserAddress).filter_by(name='Hagar').one()
1 голос
/ 12 апреля 2011

В действительности нет понятия «виртуальные таблицы», но можно отправить один запрос, который «объединяет» данные из нескольких таблиц.Это, вероятно, как можно ближе к тому, что вы хотите.

Например, один из способов сделать это в sqlalchemy / elixir будет (и это не далеко от того, что вы показали, мывы просто не запрашиваете «виртуальную» таблицу):

result = session.query(TableA, TableB).filter(TableA.a_code==x).filter(TableB.b_code==y).all()

Это похоже на внутреннее соединение SQL с некоторыми уточняющими условиями в операторах фильтра.Это не даст вам объект таблицы sqlalchemy, но даст вам список объектов из каждой реальной таблицы.

...