Простой случай:
Возможное быстрое решение: построить объект из kwargs
ваших RowProxy
, так как они объектно-подобны.
Данный:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
Мы могли бы сделать:
user = User(**dict(rowproxy.items()))
rowproxy.items()
возвращает tuples
из key-value
пар; dict(...)
преобразует tuples
в фактические key-value
пар; и User(...)
принимает kwargs
для имен атрибутов model
.
Более сложный случай:
Но что, если у вас есть model
, где один из attribute names
не совсем совпадает с SQL table
column name
? Например. что-то типа:
class User(ORMBase):
# etc...
user_id = Column(name='id', etc)
Когда мы попытаемся распаковать наш rowproxy
в класс User
, мы, скорее всего, получим ошибку следующего содержания: TypeError: 'id' is an invalid keyword argument for User
(потому что вместо этого ожидается user_id
).
Теперь это становится грязным: у нас должен лежать mapper
для того, как перейти от атрибутов table
к атрибутам model
и наоборот:
kw_map = {a.key: a.class_attribute.name for a in User.__mapper__.attrs}
Здесь a.key
— это model attribute
(и kwarg
), а a.class_attribute.name
— это table attribute
. Это дает нам что-то вроде:
{
"user_id": "id"
}
Что ж, мы хотим фактически предоставить значения, которые мы получили от нашего rowproxy
, который, помимо предоставления объектного доступа, также позволяет доступ, подобный dict:
kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
И теперь мы можем сделать:
user = User(**kwargs)
Исправления:
- вы можете захотеть
session.commit()
сразу после вызова update().returning()
, чтобы предотвратить длительные задержки ваших изменений по сравнению с тем, когда они постоянно сохраняются в базе данных. Нет необходимости session.add(user)
позже — вы уже updated()
и вам просто нужно commit()
эту транзакцию
object
— это ключевое слово в Python, поэтому старайтесь не топтать его; при этом вы можете получить очень странное поведение; вот почему я переименовал в rowproxy
.
person
dwanderson
schedule
09.11.2017
SQLAlchemy
упустил из виду, что что-то вродеupdate-returning
, которое (обычно) возвращает всю обновляемую таблицу, не имеет простого способа сопоставления с объектами. К сожалению, для этого нет более счастливого ответа. - person dwanderson   schedule 10.11.2017obj = User(**dict(object.items()))
но, похоже, это работает не во всех случаях. - person dwanderson   schedule 10.11.2017