Как я могу определить, включен ли один PGArray в другой, используя сеансы SQLAlchemy?
-
12-09-2019 - |
Вопрос
У меня есть таблица SQLAlchemy следующим образом:
table = sql.Table('treeItems', META,
sql.Column('id', sql.Integer(), primary_key=True),
sql.Column('type', sql.String, nullable=False),
sql.Column('parentId', sql.Integer, sql.ForeignKey('treeItems.id')),
sql.Column('lineage', PGArray(sql.Integer)),
sql.Column('depth', sql.Integer),
)
Который сопоставляется с объектом следующим образом:
orm.mapper(TreeItem, TreeItem.table, polymorphic_on=TreeItem.table.c.type, polymorphic_identity='TreeItem')
Я хотел бы выбрать любой дочерний узел данного узла, поэтому я ищу SQL, который выглядит следующим образом (для родительского с pk = 2):
SELECT *
FROM "treeItems"
WHERE ARRAY[2] <@ "treeItems".lineage AND "treeItems".id != 2
ORDER BY "treeItems".lineage
Вот код SQLAlchemy / Python, который я использую, чтобы попытаться добраться до вышеупомянутого SQL без особой удачи:
arrayStr = 'ARRAY[%s]' % ','.join([str(i) for i in self.lineage])
lineageFilter = expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))
query = SESSION.query(TreeItem).filter(expr.and_(lineageFilter, TreeItem.table.c.id!=self.id))
Но вот SQL, с которым я заканчиваю (обратите внимание на отсутствие кавычек вокруг имени таблицы TreeItems в предложении where):
SELECT "treeItems".id AS "treeItems_id", "treeItems".type AS "treeItems_type", "treeItems"."parentId" AS "treeItems_parentId", "treeItems".lineage AS "treeItems_lineage", "treeItems".depth AS "treeItems_depth"
FROM "treeItems"
WHERE ARRAY[2] <@ treeItems.lineage AND "treeItems".id != %(id_1)s
Итак, теперь перейдем к вопросам:
Есть ли лучший способ сделать это, чем использовать выражение text () / Есть ли оператор или выражение в SQLAlchemy, которое может сделать <@ с помощью PGArray?
Как я могу заставить кавычки отображаться вокруг имени моей таблицы, если я должен использовать выражение text()?
Спасибо всем!
Решение
Элементы предложения SQLAlchemy имеют метод .op() для пользовательских операторов.Что недоступно, так это специальное предложение для литералов массива.Вы можете указать литерал массива с помощью literal_column:
print sql.literal_column('ARRAY[2]').op('<@')(table.c.lineage)
# ARRAY[2] <@ "treeItems".lineage
Если вам нужен лучший API для литералов массива, то вы можете создать его с помощью sqlalchemy.ext.компилятор модуль добавлен в SQLAlchemy 0.5.4.
Другие советы
В этом конкретном случае я заметил, что цитирование в SQL было связано с тем, что я использовал имя таблицы со смешанным регистром.Преобразование имени таблицы из 'TreeItems' в 'tree_items' решило проблему с цитированием, и я смог заставить мое текстовое выражение работать:
expr.text('%s <@ %s' % (arrayStr, TreeItem.table.c.lineage))
Это исправление, и приятно знать, что имена таблиц со смешанным регистром должны быть заключены в кавычки, но ответ Ants остается правильным способом решения проблемы.