#python #sqlalchemy #pyramid
#python #sqlalchemy #пирамида
Вопрос:
Я действительно новичок в Python и новичок в Pyramid (это первое, что я написал на Python), и у меня возникли проблемы с запросом к базе данных…
У меня есть следующие модели (в любом случае, относящиеся к моему вопросу):
- MetadataRef (содержит информацию о заданном типе метаданных)
- Метаданные (содержит фактические метаданные) — это дочерний элемент MetadataRef
- Пользователь (содержит пользователей) — это связано с метаданными. MetadataRef.model = ‘User’ и metadata.model_id = user.id
Мне нужен доступ к имени из MetadataRef и значению из метаданных.
Вот мой код:
class User(Base):
...
_meta = None
def meta(self):
if self._meta == None:
self._meta = {}
try:
for item in DBSession.query(MetadataRef.key, Metadata.value).
outerjoin(MetadataRef.meta).
filter(
Metadata.model_id == self.id,
MetadataRef.model == 'User'
):
self._meta[item.key] = item.value
except DBAPIError:
#@TODO: actually do something with this
self._meta = {}
return self._meta
Генерируемый SQLAlchemy запрос возвращает то, что мне нужно (в любом случае, достаточно близко — ему нужно запросить model_id как часть предложения ON, а не WHERE , но это незначительно, и я почти уверен, что смогу разобраться с этим сам):
SELECT metadata_refs.`key` AS metadata_refs_key, metadata.value AS metadata_value
FROM metadata_refs LEFT OUTER JOIN metadata ON metadata_refs.id = metadata.metadata_ref_id
WHERE metadata.model_id = %s AND metadata_refs.model = %s
Однако, когда я обращаюсь к объектам, я получаю эту ошибку:
AttributeError: 'KeyedTuple' object has no attribute 'metadata_value'
Это наводит меня на мысль, что есть какой-то другой способ, которым мне нужно получить к нему доступ, но я не могу понять, как. Я пробовал оба .value
и .metadata_value
. .key
работает так, как ожидалось.
Есть идеи?
Ответ №1:
Вы запрашиваете отдельные атрибуты («дескрипторы с поддержкой ORM» в документах SA):
DBSession.query(MetadataRef.key, Metadata.value)
в этом случае запрос возвращает не полные объекты, отображенные ORM, а KeyedTuple, который представляет собой нечто среднее между кортежем и объектом с атрибутами, соответствующими «меткам» полей.
Итак, один из способов доступа к данным — это их индекс:
ref_key = item[0]
metadata_value = item[1]
В качестве альтернативы, чтобы заставить SA использовать определенное имя для столбца, вы можете использовать метод Column.label():
for item in DBSession.query(MetadataRef.key.label('ref_key'), Metadata.value.label('meta_value'))...
self._meta[item.key] = item.meta_value
Для отладки вы можете использовать метод Query.column_descriptions(), который сообщит вам имена столбцов, возвращаемых запросом.
Комментарии:
1. О, я не понимал, что к нему нужно обращаться по числовому индексу — мне не нравится зависеть от порядка столбцов, если я хочу добавить другие произвольные столбцы в запрос, поэтому ваше альтернативное решение — это именно то, что я ищу, спасибо!
2. Вам не нужно обращаться к нему через числовой индекс — кортеж с ключом позволяет получить доступ и через
obj.attribute
синтаксис — вторая половина моего ответа объясняет, как заставить его работать.