From: Mike Bayer Date: Fri, 20 Aug 2021 14:28:16 +0000 (-0400) Subject: heads up that execute(query).first() can't apply LIMIT 1 X-Git-Tag: rel_1_4_24~66 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=680baea6b83c497e862f3f0ade28e11940cfd895;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git heads up that execute(query).first() can't apply LIMIT 1 Fixes: #6914 Change-Id: I5de9843dd3723c017b94b705fc009b883737ede1 --- diff --git a/doc/build/changelog/migration_20.rst b/doc/build/changelog/migration_20.rst index 71939f44f6..e6c9e29520 100644 --- a/doc/build/changelog/migration_20.rst +++ b/doc/build/changelog/migration_20.rst @@ -1227,6 +1227,24 @@ following the table, and may include additional notes not summarized here. :meth:`_engine.Result.scalar_one` + * - :: + + session.query(User).\ + filter_by(name='some user').first() + + + - :: + + session.execute( + select(User). + filter_by(name="some user"). + limit(1) + ).scalars().first() + + - :ref:`migration_20_unify_select` + + :meth:`_engine.Result.first` + * - :: session.query(User).options( @@ -1361,6 +1379,9 @@ Legacy code examples are illustrated below:: # becomes legacy use case user = session.query(User).filter_by(name='some user').one() + # becomes legacy use case + user = session.query(User).filter_by(name='some user').first() + # becomes legacy use case user = session.query(User).get(5) @@ -1422,6 +1443,11 @@ Below are some examples of how to migrate to :func:`_sql.select`:: select(User).filter_by(name="some user") ).scalar_one() + # for first(), no LIMIT is applied automatically; add limit(1) if LIMIT + # is desired on the query + user = session.execute( + select(User).filter_by(name="some user").limit(1) + ).scalars().first() # get() moves to the Session directly user = session.get(User, 5) @@ -1846,21 +1872,22 @@ As is the case described at :ref:`migration_20_query_from_self`, the from sqlalchemy.orm import aliased - subquery = session.query(User).filter(User.id == 5).subquery() + subquery = session.query(User).filter(User.name.like("%somename%")).subquery() ua = aliased(User, subquery) - user = session.query(ua).first() + user = session.query(ua).order_by(ua.id).first() Using :term:`2.0 style`:: from sqlalchemy.orm import aliased - subquery = select(User).where(User.id == 5).subquery() + subquery = select(User).where(User.name.like("%somename%")).subquery() ua = aliased(User, subquery) - user = session.execute(select(ua)).scalars().first() + # note that LIMIT 1 is not automatically supplied, if needed + user = session.execute(select(ua).order_by(ua.id).limit(1)).scalars().first() **Discussion** diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py index 60474c0edc..3c2e682be6 100644 --- a/lib/sqlalchemy/engine/result.py +++ b/lib/sqlalchemy/engine/result.py @@ -1054,6 +1054,17 @@ class Result(_WithKeys, ResultInternal): column of the first row, use the :meth:`.Result.scalar` method, or combine :meth:`.Result.scalars` and :meth:`.Result.first`. + Additionally, in contrast to the behavior of the legacy ORM + :meth:`_orm.Query.first` method, **no limit is applied** to the + SQL query which was invoked to produce this :class:`_engine.Result`; + for a DBAPI driver that buffers results in memory before yielding + rows, all rows will be sent to the Python process and all but + the first row will be discarded. + + .. seealso:: + + :ref:`migration_20_unify_select` + :return: a :class:`.Row` object, or None if no rows remain.