Simple case:
Possible quick solution: construct the object from kwargs
of your RowProxy
, since those are object-like.
Given:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
We might be able to do:
user = User(**dict(rowproxy.items()))
rowproxy.items()
returns tuples
of key-value
pairs; dict(...)
converts the tuples
into actual key-value
pairs; and User(...)
takes kwargs
for the model
attribute names.
More difficult case:
But what if you have a model
where one of the attribute names
isn't quite the same as the SQL table
column name
? E.g. something like:
class User(ORMBase):
# etc...
user_id = Column(name='id', etc)
When we try to unpack our rowproxy
into the User
class, we'll likely get an error along the lines of: TypeError: 'id' is an invalid keyword argument for User
(because it's expecting user_id
instead).
Now it gets dirty: we should have lying around a mapper
for how to get from the table
attributes to the model
attributes and vice versa:
kw_map = {a.key: a.class_attribute.name for a in User.__mapper__.attrs}
Here, a.key
is the model attribute
(and kwarg
), and a.class_attribute.name
is the table attribute
. This gives us something like:
{
"user_id": "id"
}
Well, we want to actually provide the values we got back from our rowproxy
, which besides allowing object-like access also allows dict-like access:
kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
And now we can do:
user = User(**kwargs)
Errata:
- you may want to
session.commit()
right after calling update().returning()
to prevent long delays from your changes vs. when they get permanently stored in the database. No need to session.add(user)
later - you already updated()
and just need to commit()
that transaction
object
is a keyword in Python, so try not to stomp on it; you could get some very bizarre behavior doing that; that's why I renamed to rowproxy
.
SQLAlchemy
that something likeupdate-returning
, which (typically) returns the whole table being updated, doesn't have a simple way to map back to objects. Unfortunate there's not a happier answer for this. – Toothsomeobj = User(**dict(object.items()))
but it doesn't appear to work in all instances. – Toothsome