summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-08-20 10:28:16 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2021-08-20 11:27:47 -0400
commit680baea6b83c497e862f3f0ade28e11940cfd895 (patch)
treec38f17898e5fa30f19bf4881f21b934cbd6bb316
parent5c4a74fc13ca28983706a76ab02ffe09d89d1dbf (diff)
downloadsqlalchemy-680baea6b83c497e862f3f0ade28e11940cfd895.tar.gz
heads up that execute(query).first() can't apply LIMIT 1
Fixes: #6914 Change-Id: I5de9843dd3723c017b94b705fc009b883737ede1
-rw-r--r--doc/build/changelog/migration_20.rst35
-rw-r--r--lib/sqlalchemy/engine/result.py11
2 files changed, 42 insertions, 4 deletions
diff --git a/doc/build/changelog/migration_20.rst b/doc/build/changelog/migration_20.rst
index 71939f44f..e6c9e2952 100644
--- a/doc/build/changelog/migration_20.rst
+++ b/doc/build/changelog/migration_20.rst
@@ -1229,6 +1229,24 @@ following the table, and may include additional notes not summarized here.
* - ::
+ 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(
joinedload(User.addresses)
).all()
@@ -1362,6 +1380,9 @@ Legacy code examples are illustrated below::
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)
# becomes legacy use case
@@ -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 60474c0ed..3c2e682be 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.