since it will be very hard to change this after 2.0 is released I will try to further attempt to get ORM objects to be returned, though this will not at first support any special features:
https://github.com/sqlalchemy/sqlalchemy/issues/7865 this will allow retunring(User) to send back an instance but there's a lot of cases to be worked out. On Mon, Mar 28, 2022, at 2:05 PM, Mike Bayer wrote: > > > On Mon, Mar 28, 2022, at 1:31 PM, mkmo...@gmail.com wrote: >> Hi Mike, >> >> When using `column_property`, this >> `select(User).from_statement(ins.returing(User))` construct will not load in >> the column property. Instead the ORM will issue a second query when the >> column property is accessed. >> >> I am able to get it working using the following: >> `select(User).from_statement(ins.returing(*select(User).selected_columns))` >> >> I get your point that there may not be much of a demand for this, but I >> would argue that it is a bit unexpected for `returning(User)` to return a >> Core row, and that the solution is bit unintuitive. > > as I already agreed, it is unintuitive for now, but it's not clear it can be > made fully automatic. it would be potentially a very large job for something > that can already be achieved right now with a little more API use. > > >> >> I think it should be as easy as .returning(User) and it should return >> the full ORM model with column_properties preloaded. > > this remains a non-trivial improvement that is not on the timeline right now, > so you will have to work with what we have. > > >> >> This proposed change is backwards incompatible right? E.g. if people are >> depending on `returning(User)` returning a core Row in 2.0, is it OK to >> change this to return a Model instance in 2.1? > > not really sure, this is part of the problem. we reserve the right to make > backwards incompatible changes in a the middle point since we are not on > semver. as returning(User) is not that intuitive when the documented > approach isn't used, we will assume people are not using that form very much > should we decide to implement this feature. > >> >> By the way, I think I found a bug with insert().values() when the ORM uses >> different field names than the Database column names. update().values() >> works fine, but not insert().values(). Please check my issue here when you >> have a moment. > > that can likely be improved for 2.0. > >> >> https://github.com/sqlalchemy/sqlalchemy/issues/7864 >> >> ------ >> >> Here is how to reproduce the case where column_property results in an extra >> query, if you are interested: > > sure, there's a very complex process that's used to SELECT all columns. your > use case should work right now if you do something like this: > > select(User).from_statement(insert(User).returning(User, > User.my_column_property)) > > > > >> >> class User(Base): >> __tablename__ = 'users' >> id = Column(Integer, primary_key=True) >> first_name = Column(String(30)) >> last_name = Column(String(30)) >> full_name = column_property(first_name + " " + last_name) >> >> # returning(User) triggers extra query on column_property access >> res = >> session.execute(select(User).from_statement(insert(User).values(first_name='foo', >> last_name='bar').returning(User))) >> user = res.scalars().one() >> # This triggers a select >> print(user.full_name) >> >> session.expunge(user) >> >> # normal query does not trigger a select as expected >> res = session.execute(select(User).where(User.id == user.id)) >> user = res.scalars().one() >> print(user.full_name) >> >> session.expunge(user) >> >> # use *selected(User).selected_columns to avoid triggering an extra >> select >> res = >> session.execute(select(User).from_statement(update(User).values(first_name='foo2').where(User.id >> == user.id).returning(*select(User).selected_columns))) >> user = res.scalars().one() >> # no extra query >> print(user.full_name) >> >> Thanks and best regards, >> >> Matthew >> >> >> On Sunday, March 27, 2022 at 7:28:55 PM UTC-7 Mike Bayer wrote: >>> >>> >>> On Sun, Mar 27, 2022, at 2:56 PM, mkmo...@gmail.com wrote: >>>> Hi Mike, >>>> >>>> I'm writing a library that uses SQLAlchemy. The user will pass the library >>>> an update, and the library will add a RETURNING clause for postgresql >>>> users, and then return the model back to the user. The idea here is to >>>> update and select the row in a single database call, instead of the normal >>>> approach where two calls are made. >>>> >>>> However, `upd.returning(User)` will actually return a Core row, not the >>>> ORM model instance: >>>> >>>> upd = update(User).values(name='foo').where(User.id == >>>> 1).returning(User) >>>> result = session.execute(upd) >>>> row = result.one() >>>> assert isinstance(row, Row) >>>> >>>> The key question I have is how to convert a Core row into an ORM model >>>> instance. >>>> >>> >>> use the construct select(User).from_statement(update(User)...returning()) . >>> See the example at >>> https://docs.sqlalchemy.org/en/14/orm/persistence_techniques.html#using-insert-update-and-on-conflict-i-e-upsert-to-return-orm-objects >>> >>> >>> >>>> >>>> `model(**row._mapping)` fails in at least these two cases: different >>>> field name in ORM vs database, and column_property. >>>> >>>> I also wonder, should SQLAlchemy return the Model instead of the core row >>>> in this case? >>> >>> unknown at this time. The above link illustrates a very new technique by >>> which this can work now. if this were to become more implicit without >>> the extra step, that would at best be a 2.1 thing not expected for at least >>> 18 months, it would be based on general demand for this kind of thing >>> (which does seem to be increasing). >>> >>> >>> >>> >>> >>> >>>> >>>> >>>> ------- >>>> >>>> I've gotten this far: >>>> >>>> model = model_from_dml(upd) >>>> upd = upd.returning(*select(model).selected_columns) # this will >>>> apply the column_property to the RETURNING >>>> row = session.execute(upd).one() >>>> >>>> Now I just need to take this row and convert it to an ORM object. >>>> >>>> Is there a public API I can use to take a Core `row` and convert it to an >>>> ORM model? >>>> >>>> Thanks and best regards, >>>> >>>> Matthew >>>> On Sunday, March 27, 2022 at 11:11:30 AM UTC-7 Mike Bayer wrote: >>>>> >>>>> >>>>> On Sun, Mar 27, 2022, at 2:08 PM, mkmo...@gmail.com wrote: >>>>>> Hi Mike, >>>>>> >>>>>> Thanks. Should I use column_descriptions[0]['type'] ? >>>>> >>>>> yup, that should be pretty consistent in this case. >>>>> >>>>> I've implemented most of an actual feature for this but isn't committed >>>>> yet at https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/3742 >>>>> >>>>>> >>>>>> >>>>>> In my case, `type`, `expr` and `entity` all return the model class that >>>>>> I am interested in. >>>>>> >>>>>> Thanks and best regards, >>>>>> >>>>>> Matthew >>>>>> On Saturday, March 26, 2022 at 12:02:54 PM UTC-7 Mike Bayer wrote: >>>>>>> __ >>>>>>> the Project model is actually in there, but not in a public API place >>>>>>> (this is not the solution, but look inside of table._annotations to see >>>>>>> it). >>>>>>> >>>>>>> The closest public API we have for this very new API right now is the >>>>>>> Query equivalent of column_descriptions, which is available on the >>>>>>> select() construct and works when the thing being selected is >>>>>>> ORM-enabled, and, alarmingly, it seems there is no documentation >>>>>>> whatsoever for the Select version of it, that is wrong, but anyway see >>>>>>> the 1.x docs for now: >>>>>>> https://docs.sqlalchemy.org/en/14/orm/query.html#sqlalchemy.orm.Query.column_descriptions >>>>>>> >>>>>>> This accessor would ideally be on insert, update and delete also, which >>>>>>> it currently is not. However, here's a quick way to get it right now: >>>>>>> >>>>>>> class A(Base): >>>>>>> __tablename__ = 'a' >>>>>>> >>>>>>> id = Column(Integer, primary_key=True) >>>>>>> data = Column(String) >>>>>>> >>>>>>> >>>>>>> upd = update(A) >>>>>>> >>>>>>> print(select(upd.table).column_descriptions) >>>>>>> >>>>>>> i might take a crack at cleaning this up now but the above will get you >>>>>>> what you need. >>>>>>> >>>>>>> On Sat, Mar 26, 2022, at 1:34 PM, mkmo...@gmail.com wrote: >>>>>>>> Hello, >>>>>>>> >>>>>>>> How can I infer the ORM model class from an update (or insert, or >>>>>>>> delete) function result? >>>>>>>> >>>>>>>> upd = update(Project).values(name='foo').where( >>>>>>>> Project.id == 1 >>>>>>>> ) >>>>>>>> >>>>>>>> def my_library_function(session, upd): >>>>>>>> result = session.execute(upd) >>>>>>>> # how to get the Project ORM model here, using only session and >>>>>>>> upd ? >>>>>>>> >>>>>>>> I saw that the update() object has a `table` attribute, but this >>>>>>>> returns the Core table (not the ORM model). In addition I don't have >>>>>>>> access to the base/registry from this function (unless it can be >>>>>>>> derived from session?). Moreover it seems like searching the registry >>>>>>>> is O(n) and will not work in all cases, such as when two ORM models >>>>>>>> map to the same Core table. >>>>>>>> >>>>>>>> Thanks and best regards, >>>>>>>> >>>>>>>> Matthew >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> SQLAlchemy - >>>>>>>> The Python SQL Toolkit and Object Relational Mapper >>>>>>>> >>>>>>>> http://www.sqlalchemy.org/ >>>>>>>> >>>>>>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>>>>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>>>>>> description. >>>>>>>> --- >>>>>>>> You received this message because you are subscribed to the Google >>>>>>>> Groups "sqlalchemy" group. >>>>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>>>> an email to sqlalchemy+...@googlegroups.com. >>>>>>>> To view this discussion on the web visit >>>>>>>> https://groups.google.com/d/msgid/sqlalchemy/9fc63126-a36d-4e36-b4df-50701bfcae47n%40googlegroups.com >>>>>>>> >>>>>>>> <https://groups.google.com/d/msgid/sqlalchemy/9fc63126-a36d-4e36-b4df-50701bfcae47n%40googlegroups.com?utm_medium=email&utm_source=footer>. >>>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> SQLAlchemy - >>>>>> The Python SQL Toolkit and Object Relational Mapper >>>>>> >>>>>> http://www.sqlalchemy.org/ >>>>>> >>>>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>>>> description. >>>>>> --- >>>>>> You received this message because you are subscribed to the Google >>>>>> Groups "sqlalchemy" group. >>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>> an email to sqlalchemy+...@googlegroups.com. >>>>>> To view this discussion on the web visit >>>>>> https://groups.google.com/d/msgid/sqlalchemy/abc01658-17a5-451b-aca7-0864998c5af7n%40googlegroups.com >>>>>> >>>>>> <https://groups.google.com/d/msgid/sqlalchemy/abc01658-17a5-451b-aca7-0864998c5af7n%40googlegroups.com?utm_medium=email&utm_source=footer>. >>>>> >>>> >>>> >>>> -- >>>> SQLAlchemy - >>>> The Python SQL Toolkit and Object Relational Mapper >>>> >>>> http://www.sqlalchemy.org/ >>>> >>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>> description. >>>> --- >>>> You received this message because you are subscribed to the Google Groups >>>> "sqlalchemy" group. >>>> To unsubscribe from this group and stop receiving emails from it, send an >>>> email to sqlalchemy+...@googlegroups.com. >>>> To view this discussion on the web visit >>>> https://groups.google.com/d/msgid/sqlalchemy/1ab4ec6a-aff6-4b7d-8835-6553a48a68b6n%40googlegroups.com >>>> >>>> <https://groups.google.com/d/msgid/sqlalchemy/1ab4ec6a-aff6-4b7d-8835-6553a48a68b6n%40googlegroups.com?utm_medium=email&utm_source=footer>. >>> >> >> >> -- >> SQLAlchemy - >> The Python SQL Toolkit and Object Relational Mapper >> >> http://www.sqlalchemy.org/ >> >> To post example code, please provide an MCVE: Minimal, Complete, and >> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >> description. >> --- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to sqlalchemy+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/sqlalchemy/a2daf61e-d84f-4678-a6e4-fa96547c07f8n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/sqlalchemy/a2daf61e-d84f-4678-a6e4-fa96547c07f8n%40googlegroups.com?utm_medium=email&utm_source=footer>. > > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/f1222311-ca61-4ad4-9ff7-63ea945448b6%40www.fastmail.com > > <https://groups.google.com/d/msgid/sqlalchemy/f1222311-ca61-4ad4-9ff7-63ea945448b6%40www.fastmail.com?utm_medium=email&utm_source=footer>. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/c968c278-c0a7-4612-b6df-98b61061a66b%40www.fastmail.com.