Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/query.py: 46%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

801 statements  

1# orm/query.py 

2# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7 

8"""The Query class and support. 

9 

10Defines the :class:`_query.Query` class, the central 

11construct used by the ORM to construct database queries. 

12 

13The :class:`_query.Query` class should not be confused with the 

14:class:`_expression.Select` class, which defines database 

15SELECT operations at the SQL (non-ORM) level. ``Query`` differs from 

16``Select`` in that it returns ORM-mapped objects and interacts with an 

17ORM session, whereas the ``Select`` construct interacts directly with the 

18database to return iterable result sets. 

19 

20""" 

21from __future__ import annotations 

22 

23import collections.abc as collections_abc 

24import operator 

25from typing import Any 

26from typing import Callable 

27from typing import cast 

28from typing import Dict 

29from typing import Generic 

30from typing import Iterable 

31from typing import Iterator 

32from typing import List 

33from typing import Mapping 

34from typing import Optional 

35from typing import overload 

36from typing import Sequence 

37from typing import Tuple 

38from typing import Type 

39from typing import TYPE_CHECKING 

40from typing import TypeVar 

41from typing import Union 

42 

43from . import attributes 

44from . import interfaces 

45from . import loading 

46from . import util as orm_util 

47from ._typing import _O 

48from .base import _assertions 

49from .context import _column_descriptions 

50from .context import _determine_last_joined_entity 

51from .context import _legacy_filter_by_entity_zero 

52from .context import FromStatement 

53from .context import ORMCompileState 

54from .context import QueryContext 

55from .interfaces import ORMColumnDescription 

56from .interfaces import ORMColumnsClauseRole 

57from .util import AliasedClass 

58from .util import object_mapper 

59from .util import with_parent 

60from .. import exc as sa_exc 

61from .. import inspect 

62from .. import inspection 

63from .. import log 

64from .. import sql 

65from .. import util 

66from ..engine import Result 

67from ..engine import Row 

68from ..event import dispatcher 

69from ..event import EventTarget 

70from ..sql import coercions 

71from ..sql import expression 

72from ..sql import roles 

73from ..sql import Select 

74from ..sql import util as sql_util 

75from ..sql import visitors 

76from ..sql._typing import _FromClauseArgument 

77from ..sql._typing import _TP 

78from ..sql.annotation import SupportsCloneAnnotations 

79from ..sql.base import _entity_namespace_key 

80from ..sql.base import _generative 

81from ..sql.base import _NoArg 

82from ..sql.base import Executable 

83from ..sql.base import Generative 

84from ..sql.elements import BooleanClauseList 

85from ..sql.expression import Exists 

86from ..sql.selectable import _MemoizedSelectEntities 

87from ..sql.selectable import _SelectFromElements 

88from ..sql.selectable import ForUpdateArg 

89from ..sql.selectable import HasHints 

90from ..sql.selectable import HasPrefixes 

91from ..sql.selectable import HasSuffixes 

92from ..sql.selectable import LABEL_STYLE_TABLENAME_PLUS_COL 

93from ..sql.selectable import SelectLabelStyle 

94from ..util.typing import Literal 

95from ..util.typing import Self 

96from ..util.typing import SupportsIndex 

97 

98 

99if TYPE_CHECKING: 

100 from ._typing import _EntityType 

101 from ._typing import _ExternalEntityType 

102 from ._typing import _InternalEntityType 

103 from ._typing import SynchronizeSessionArgument 

104 from .mapper import Mapper 

105 from .path_registry import PathRegistry 

106 from .session import _PKIdentityArgument 

107 from .session import Session 

108 from .state import InstanceState 

109 from ..engine.cursor import CursorResult 

110 from ..engine.interfaces import _ImmutableExecuteOptions 

111 from ..engine.interfaces import CompiledCacheType 

112 from ..engine.interfaces import IsolationLevel 

113 from ..engine.interfaces import SchemaTranslateMapType 

114 from ..engine.result import FrozenResult 

115 from ..engine.result import ScalarResult 

116 from ..sql._typing import _ColumnExpressionArgument 

117 from ..sql._typing import _ColumnExpressionOrStrLabelArgument 

118 from ..sql._typing import _ColumnsClauseArgument 

119 from ..sql._typing import _DMLColumnArgument 

120 from ..sql._typing import _JoinTargetArgument 

121 from ..sql._typing import _LimitOffsetType 

122 from ..sql._typing import _MAYBE_ENTITY 

123 from ..sql._typing import _no_kw 

124 from ..sql._typing import _NOT_ENTITY 

125 from ..sql._typing import _OnClauseArgument 

126 from ..sql._typing import _PropagateAttrsType 

127 from ..sql._typing import _T0 

128 from ..sql._typing import _T1 

129 from ..sql._typing import _T2 

130 from ..sql._typing import _T3 

131 from ..sql._typing import _T4 

132 from ..sql._typing import _T5 

133 from ..sql._typing import _T6 

134 from ..sql._typing import _T7 

135 from ..sql._typing import _TypedColumnClauseArgument as _TCCA 

136 from ..sql.base import CacheableOptions 

137 from ..sql.base import ExecutableOption 

138 from ..sql.dml import UpdateBase 

139 from ..sql.elements import ColumnElement 

140 from ..sql.elements import Label 

141 from ..sql.selectable import _ForUpdateOfArgument 

142 from ..sql.selectable import _JoinTargetElement 

143 from ..sql.selectable import _SetupJoinsElement 

144 from ..sql.selectable import Alias 

145 from ..sql.selectable import CTE 

146 from ..sql.selectable import ExecutableReturnsRows 

147 from ..sql.selectable import FromClause 

148 from ..sql.selectable import ScalarSelect 

149 from ..sql.selectable import Subquery 

150 

151 

152__all__ = ["Query", "QueryContext"] 

153 

154_T = TypeVar("_T", bound=Any) 

155 

156 

157@inspection._self_inspects 

158@log.class_logger 

159class Query( 

160 _SelectFromElements, 

161 SupportsCloneAnnotations, 

162 HasPrefixes, 

163 HasSuffixes, 

164 HasHints, 

165 EventTarget, 

166 log.Identified, 

167 Generative, 

168 Executable, 

169 Generic[_T], 

170): 

171 """ORM-level SQL construction object. 

172 

173 .. legacy:: The ORM :class:`.Query` object is a legacy construct 

174 as of SQLAlchemy 2.0. See the notes at the top of 

175 :ref:`query_api_toplevel` for an overview, including links to migration 

176 documentation. 

177 

178 :class:`_query.Query` objects are normally initially generated using the 

179 :meth:`~.Session.query` method of :class:`.Session`, and in 

180 less common cases by instantiating the :class:`_query.Query` directly and 

181 associating with a :class:`.Session` using the 

182 :meth:`_query.Query.with_session` 

183 method. 

184 

185 """ 

186 

187 # elements that are in Core and can be cached in the same way 

188 _where_criteria: Tuple[ColumnElement[Any], ...] = () 

189 _having_criteria: Tuple[ColumnElement[Any], ...] = () 

190 

191 _order_by_clauses: Tuple[ColumnElement[Any], ...] = () 

192 _group_by_clauses: Tuple[ColumnElement[Any], ...] = () 

193 _limit_clause: Optional[ColumnElement[Any]] = None 

194 _offset_clause: Optional[ColumnElement[Any]] = None 

195 

196 _distinct: bool = False 

197 _distinct_on: Tuple[ColumnElement[Any], ...] = () 

198 

199 _for_update_arg: Optional[ForUpdateArg] = None 

200 _correlate: Tuple[FromClause, ...] = () 

201 _auto_correlate: bool = True 

202 _from_obj: Tuple[FromClause, ...] = () 

203 _setup_joins: Tuple[_SetupJoinsElement, ...] = () 

204 

205 _label_style: SelectLabelStyle = SelectLabelStyle.LABEL_STYLE_LEGACY_ORM 

206 

207 _memoized_select_entities = () 

208 

209 _compile_options: Union[Type[CacheableOptions], CacheableOptions] = ( 

210 ORMCompileState.default_compile_options 

211 ) 

212 

213 _with_options: Tuple[ExecutableOption, ...] 

214 load_options = QueryContext.default_load_options + { 

215 "_legacy_uniquing": True 

216 } 

217 

218 _params: util.immutabledict[str, Any] = util.EMPTY_DICT 

219 

220 # local Query builder state, not needed for 

221 # compilation or execution 

222 _enable_assertions = True 

223 

224 _statement: Optional[ExecutableReturnsRows] = None 

225 

226 session: Session 

227 

228 dispatch: dispatcher[Query[_T]] 

229 

230 # mirrors that of ClauseElement, used to propagate the "orm" 

231 # plugin as well as the "subject" of the plugin, e.g. the mapper 

232 # we are querying against. 

233 @util.memoized_property 

234 def _propagate_attrs(self) -> _PropagateAttrsType: 

235 return util.EMPTY_DICT 

236 

237 def __init__( 

238 self, 

239 entities: Union[ 

240 _ColumnsClauseArgument[Any], Sequence[_ColumnsClauseArgument[Any]] 

241 ], 

242 session: Optional[Session] = None, 

243 ): 

244 """Construct a :class:`_query.Query` directly. 

245 

246 E.g.:: 

247 

248 q = Query([User, Address], session=some_session) 

249 

250 The above is equivalent to:: 

251 

252 q = some_session.query(User, Address) 

253 

254 :param entities: a sequence of entities and/or SQL expressions. 

255 

256 :param session: a :class:`.Session` with which the 

257 :class:`_query.Query` 

258 will be associated. Optional; a :class:`_query.Query` 

259 can be associated 

260 with a :class:`.Session` generatively via the 

261 :meth:`_query.Query.with_session` method as well. 

262 

263 .. seealso:: 

264 

265 :meth:`.Session.query` 

266 

267 :meth:`_query.Query.with_session` 

268 

269 """ 

270 

271 # session is usually present. There's one case in subqueryloader 

272 # where it stores a Query without a Session and also there are tests 

273 # for the query(Entity).with_session(session) API which is likely in 

274 # some old recipes, however these are legacy as select() can now be 

275 # used. 

276 self.session = session # type: ignore 

277 self._set_entities(entities) 

278 

279 def _set_propagate_attrs(self, values: Mapping[str, Any]) -> Self: 

280 self._propagate_attrs = util.immutabledict(values) 

281 return self 

282 

283 def _set_entities( 

284 self, 

285 entities: Union[ 

286 _ColumnsClauseArgument[Any], Iterable[_ColumnsClauseArgument[Any]] 

287 ], 

288 ) -> None: 

289 self._raw_columns = [ 

290 coercions.expect( 

291 roles.ColumnsClauseRole, 

292 ent, 

293 apply_propagate_attrs=self, 

294 post_inspect=True, 

295 ) 

296 for ent in util.to_list(entities) 

297 ] 

298 

299 def tuples(self: Query[_O]) -> Query[Tuple[_O]]: 

300 """return a tuple-typed form of this :class:`.Query`. 

301 

302 This method invokes the :meth:`.Query.only_return_tuples` 

303 method with a value of ``True``, which by itself ensures that this 

304 :class:`.Query` will always return :class:`.Row` objects, even 

305 if the query is made against a single entity. It then also 

306 at the typing level will return a "typed" query, if possible, 

307 that will type result rows as ``Tuple`` objects with typed 

308 elements. 

309 

310 This method can be compared to the :meth:`.Result.tuples` method, 

311 which returns "self", but from a typing perspective returns an object 

312 that will yield typed ``Tuple`` objects for results. Typing 

313 takes effect only if this :class:`.Query` object is a typed 

314 query object already. 

315 

316 .. versionadded:: 2.0 

317 

318 .. seealso:: 

319 

320 :meth:`.Result.tuples` - v2 equivalent method. 

321 

322 """ 

323 return self.only_return_tuples(True) # type: ignore 

324 

325 def _entity_from_pre_ent_zero(self) -> Optional[_InternalEntityType[Any]]: 

326 if not self._raw_columns: 

327 return None 

328 

329 ent = self._raw_columns[0] 

330 

331 if "parententity" in ent._annotations: 

332 return ent._annotations["parententity"] # type: ignore 

333 elif "bundle" in ent._annotations: 

334 return ent._annotations["bundle"] # type: ignore 

335 else: 

336 # label, other SQL expression 

337 for element in visitors.iterate(ent): 

338 if "parententity" in element._annotations: 

339 return element._annotations["parententity"] # type: ignore # noqa: E501 

340 else: 

341 return None 

342 

343 def _only_full_mapper_zero(self, methname: str) -> Mapper[Any]: 

344 if ( 

345 len(self._raw_columns) != 1 

346 or "parententity" not in self._raw_columns[0]._annotations 

347 or not self._raw_columns[0].is_selectable 

348 ): 

349 raise sa_exc.InvalidRequestError( 

350 "%s() can only be used against " 

351 "a single mapped class." % methname 

352 ) 

353 

354 return self._raw_columns[0]._annotations["parententity"] # type: ignore # noqa: E501 

355 

356 def _set_select_from( 

357 self, obj: Iterable[_FromClauseArgument], set_base_alias: bool 

358 ) -> None: 

359 fa = [ 

360 coercions.expect( 

361 roles.StrictFromClauseRole, 

362 elem, 

363 allow_select=True, 

364 apply_propagate_attrs=self, 

365 ) 

366 for elem in obj 

367 ] 

368 

369 self._compile_options += {"_set_base_alias": set_base_alias} 

370 self._from_obj = tuple(fa) 

371 

372 @_generative 

373 def _set_lazyload_from(self, state: InstanceState[Any]) -> Self: 

374 self.load_options += {"_lazy_loaded_from": state} 

375 return self 

376 

377 def _get_condition(self) -> None: 

378 """used by legacy BakedQuery""" 

379 self._no_criterion_condition("get", order_by=False, distinct=False) 

380 

381 def _get_existing_condition(self) -> None: 

382 self._no_criterion_assertion("get", order_by=False, distinct=False) 

383 

384 def _no_criterion_assertion( 

385 self, meth: str, order_by: bool = True, distinct: bool = True 

386 ) -> None: 

387 if not self._enable_assertions: 

388 return 

389 if ( 

390 self._where_criteria 

391 or self._statement is not None 

392 or self._from_obj 

393 or self._setup_joins 

394 or self._limit_clause is not None 

395 or self._offset_clause is not None 

396 or self._group_by_clauses 

397 or (order_by and self._order_by_clauses) 

398 or (distinct and self._distinct) 

399 ): 

400 raise sa_exc.InvalidRequestError( 

401 "Query.%s() being called on a " 

402 "Query with existing criterion. " % meth 

403 ) 

404 

405 def _no_criterion_condition( 

406 self, meth: str, order_by: bool = True, distinct: bool = True 

407 ) -> None: 

408 self._no_criterion_assertion(meth, order_by, distinct) 

409 

410 self._from_obj = self._setup_joins = () 

411 if self._statement is not None: 

412 self._compile_options += {"_statement": None} 

413 self._where_criteria = () 

414 self._distinct = False 

415 

416 self._order_by_clauses = self._group_by_clauses = () 

417 

418 def _no_clauseelement_condition(self, meth: str) -> None: 

419 if not self._enable_assertions: 

420 return 

421 if self._order_by_clauses: 

422 raise sa_exc.InvalidRequestError( 

423 "Query.%s() being called on a " 

424 "Query with existing criterion. " % meth 

425 ) 

426 self._no_criterion_condition(meth) 

427 

428 def _no_statement_condition(self, meth: str) -> None: 

429 if not self._enable_assertions: 

430 return 

431 if self._statement is not None: 

432 raise sa_exc.InvalidRequestError( 

433 ( 

434 "Query.%s() being called on a Query with an existing full " 

435 "statement - can't apply criterion." 

436 ) 

437 % meth 

438 ) 

439 

440 def _no_limit_offset(self, meth: str) -> None: 

441 if not self._enable_assertions: 

442 return 

443 if self._limit_clause is not None or self._offset_clause is not None: 

444 raise sa_exc.InvalidRequestError( 

445 "Query.%s() being called on a Query which already has LIMIT " 

446 "or OFFSET applied. Call %s() before limit() or offset() " 

447 "are applied." % (meth, meth) 

448 ) 

449 

450 @property 

451 def _has_row_limiting_clause(self) -> bool: 

452 return ( 

453 self._limit_clause is not None or self._offset_clause is not None 

454 ) 

455 

456 def _get_options( 

457 self, 

458 populate_existing: Optional[bool] = None, 

459 version_check: Optional[bool] = None, 

460 only_load_props: Optional[Sequence[str]] = None, 

461 refresh_state: Optional[InstanceState[Any]] = None, 

462 identity_token: Optional[Any] = None, 

463 ) -> Self: 

464 load_options: Dict[str, Any] = {} 

465 compile_options: Dict[str, Any] = {} 

466 

467 if version_check: 

468 load_options["_version_check"] = version_check 

469 if populate_existing: 

470 load_options["_populate_existing"] = populate_existing 

471 if refresh_state: 

472 load_options["_refresh_state"] = refresh_state 

473 compile_options["_for_refresh_state"] = True 

474 if only_load_props: 

475 compile_options["_only_load_props"] = frozenset(only_load_props) 

476 if identity_token: 

477 load_options["_identity_token"] = identity_token 

478 

479 if load_options: 

480 self.load_options += load_options 

481 if compile_options: 

482 self._compile_options += compile_options 

483 

484 return self 

485 

486 def _clone(self, **kw: Any) -> Self: 

487 return self._generate() 

488 

489 def _get_select_statement_only(self) -> Select[_T]: 

490 if self._statement is not None: 

491 raise sa_exc.InvalidRequestError( 

492 "Can't call this method on a Query that uses from_statement()" 

493 ) 

494 return cast("Select[_T]", self.statement) 

495 

496 @property 

497 def statement(self) -> Union[Select[_T], FromStatement[_T], UpdateBase]: 

498 """The full SELECT statement represented by this Query. 

499 

500 The statement by default will not have disambiguating labels 

501 applied to the construct unless with_labels(True) is called 

502 first. 

503 

504 """ 

505 

506 # .statement can return the direct future.Select() construct here, as 

507 # long as we are not using subsequent adaption features that 

508 # are made against raw entities, e.g. from_self(), with_polymorphic(), 

509 # select_entity_from(). If these features are being used, then 

510 # the Select() we return will not have the correct .selected_columns 

511 # collection and will not embed in subsequent queries correctly. 

512 # We could find a way to make this collection "correct", however 

513 # this would not be too different from doing the full compile as 

514 # we are doing in any case, the Select() would still not have the 

515 # proper state for other attributes like whereclause, order_by, 

516 # and these features are all deprecated in any case. 

517 # 

518 # for these reasons, Query is not a Select, it remains an ORM 

519 # object for which __clause_element__() must be called in order for 

520 # it to provide a real expression object. 

521 # 

522 # from there, it starts to look much like Query itself won't be 

523 # passed into the execute process and won't generate its own cache 

524 # key; this will all occur in terms of the ORM-enabled Select. 

525 stmt: Union[Select[_T], FromStatement[_T], UpdateBase] 

526 

527 if not self._compile_options._set_base_alias: 

528 # if we don't have legacy top level aliasing features in use 

529 # then convert to a future select() directly 

530 stmt = self._statement_20(for_statement=True) 

531 else: 

532 stmt = self._compile_state(for_statement=True).statement 

533 

534 if self._params: 

535 stmt = stmt.params(self._params) 

536 

537 return stmt 

538 

539 def _final_statement(self, legacy_query_style: bool = True) -> Select[Any]: 

540 """Return the 'final' SELECT statement for this :class:`.Query`. 

541 

542 This is used by the testing suite only and is fairly inefficient. 

543 

544 This is the Core-only select() that will be rendered by a complete 

545 compilation of this query, and is what .statement used to return 

546 in 1.3. 

547 

548 

549 """ 

550 

551 q = self._clone() 

552 

553 return q._compile_state( 

554 use_legacy_query_style=legacy_query_style 

555 ).statement # type: ignore 

556 

557 def _statement_20( 

558 self, for_statement: bool = False, use_legacy_query_style: bool = True 

559 ) -> Union[Select[_T], FromStatement[_T]]: 

560 # TODO: this event needs to be deprecated, as it currently applies 

561 # only to ORM query and occurs at this spot that is now more 

562 # or less an artificial spot 

563 if self.dispatch.before_compile: 

564 for fn in self.dispatch.before_compile: 

565 new_query = fn(self) 

566 if new_query is not None and new_query is not self: 

567 self = new_query 

568 if not fn._bake_ok: # type: ignore 

569 self._compile_options += {"_bake_ok": False} 

570 

571 compile_options = self._compile_options 

572 compile_options += { 

573 "_for_statement": for_statement, 

574 "_use_legacy_query_style": use_legacy_query_style, 

575 } 

576 

577 stmt: Union[Select[_T], FromStatement[_T]] 

578 

579 if self._statement is not None: 

580 stmt = FromStatement(self._raw_columns, self._statement) 

581 stmt.__dict__.update( 

582 _with_options=self._with_options, 

583 _with_context_options=self._with_context_options, 

584 _compile_options=compile_options, 

585 _execution_options=self._execution_options, 

586 _propagate_attrs=self._propagate_attrs, 

587 ) 

588 else: 

589 # Query / select() internal attributes are 99% cross-compatible 

590 stmt = Select._create_raw_select(**self.__dict__) 

591 stmt.__dict__.update( 

592 _label_style=self._label_style, 

593 _compile_options=compile_options, 

594 _propagate_attrs=self._propagate_attrs, 

595 ) 

596 stmt.__dict__.pop("session", None) 

597 

598 # ensure the ORM context is used to compile the statement, even 

599 # if it has no ORM entities. This is so ORM-only things like 

600 # _legacy_joins are picked up that wouldn't be picked up by the 

601 # Core statement context 

602 if "compile_state_plugin" not in stmt._propagate_attrs: 

603 stmt._propagate_attrs = stmt._propagate_attrs.union( 

604 {"compile_state_plugin": "orm", "plugin_subject": None} 

605 ) 

606 

607 return stmt 

608 

609 def subquery( 

610 self, 

611 name: Optional[str] = None, 

612 with_labels: bool = False, 

613 reduce_columns: bool = False, 

614 ) -> Subquery: 

615 """Return the full SELECT statement represented by 

616 this :class:`_query.Query`, embedded within an 

617 :class:`_expression.Alias`. 

618 

619 Eager JOIN generation within the query is disabled. 

620 

621 .. seealso:: 

622 

623 :meth:`_sql.Select.subquery` - v2 comparable method. 

624 

625 :param name: string name to be assigned as the alias; 

626 this is passed through to :meth:`_expression.FromClause.alias`. 

627 If ``None``, a name will be deterministically generated 

628 at compile time. 

629 

630 :param with_labels: if True, :meth:`.with_labels` will be called 

631 on the :class:`_query.Query` first to apply table-qualified labels 

632 to all columns. 

633 

634 :param reduce_columns: if True, 

635 :meth:`_expression.Select.reduce_columns` will 

636 be called on the resulting :func:`_expression.select` construct, 

637 to remove same-named columns where one also refers to the other 

638 via foreign key or WHERE clause equivalence. 

639 

640 """ 

641 q = self.enable_eagerloads(False) 

642 if with_labels: 

643 q = q.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

644 

645 stmt = q._get_select_statement_only() 

646 

647 if TYPE_CHECKING: 

648 assert isinstance(stmt, Select) 

649 

650 if reduce_columns: 

651 stmt = stmt.reduce_columns() 

652 return stmt.subquery(name=name) 

653 

654 def cte( 

655 self, 

656 name: Optional[str] = None, 

657 recursive: bool = False, 

658 nesting: bool = False, 

659 ) -> CTE: 

660 r"""Return the full SELECT statement represented by this 

661 :class:`_query.Query` represented as a common table expression (CTE). 

662 

663 Parameters and usage are the same as those of the 

664 :meth:`_expression.SelectBase.cte` method; see that method for 

665 further details. 

666 

667 Here is the `PostgreSQL WITH 

668 RECURSIVE example 

669 <https://www.postgresql.org/docs/current/static/queries-with.html>`_. 

670 Note that, in this example, the ``included_parts`` cte and the 

671 ``incl_alias`` alias of it are Core selectables, which 

672 means the columns are accessed via the ``.c.`` attribute. The 

673 ``parts_alias`` object is an :func:`_orm.aliased` instance of the 

674 ``Part`` entity, so column-mapped attributes are available 

675 directly:: 

676 

677 from sqlalchemy.orm import aliased 

678 

679 

680 class Part(Base): 

681 __tablename__ = "part" 

682 part = Column(String, primary_key=True) 

683 sub_part = Column(String, primary_key=True) 

684 quantity = Column(Integer) 

685 

686 

687 included_parts = ( 

688 session.query(Part.sub_part, Part.part, Part.quantity) 

689 .filter(Part.part == "our part") 

690 .cte(name="included_parts", recursive=True) 

691 ) 

692 

693 incl_alias = aliased(included_parts, name="pr") 

694 parts_alias = aliased(Part, name="p") 

695 included_parts = included_parts.union_all( 

696 session.query( 

697 parts_alias.sub_part, parts_alias.part, parts_alias.quantity 

698 ).filter(parts_alias.part == incl_alias.c.sub_part) 

699 ) 

700 

701 q = session.query( 

702 included_parts.c.sub_part, 

703 func.sum(included_parts.c.quantity).label("total_quantity"), 

704 ).group_by(included_parts.c.sub_part) 

705 

706 .. seealso:: 

707 

708 :meth:`_sql.Select.cte` - v2 equivalent method. 

709 

710 """ # noqa: E501 

711 return ( 

712 self.enable_eagerloads(False) 

713 ._get_select_statement_only() 

714 .cte(name=name, recursive=recursive, nesting=nesting) 

715 ) 

716 

717 def label(self, name: Optional[str]) -> Label[Any]: 

718 """Return the full SELECT statement represented by this 

719 :class:`_query.Query`, converted 

720 to a scalar subquery with a label of the given name. 

721 

722 .. seealso:: 

723 

724 :meth:`_sql.Select.label` - v2 comparable method. 

725 

726 """ 

727 

728 return ( 

729 self.enable_eagerloads(False) 

730 ._get_select_statement_only() 

731 .label(name) 

732 ) 

733 

734 @overload 

735 def as_scalar( # type: ignore[overload-overlap] 

736 self: Query[Tuple[_MAYBE_ENTITY]], 

737 ) -> ScalarSelect[_MAYBE_ENTITY]: ... 

738 

739 @overload 

740 def as_scalar( 

741 self: Query[Tuple[_NOT_ENTITY]], 

742 ) -> ScalarSelect[_NOT_ENTITY]: ... 

743 

744 @overload 

745 def as_scalar(self) -> ScalarSelect[Any]: ... 

746 

747 @util.deprecated( 

748 "1.4", 

749 "The :meth:`_query.Query.as_scalar` method is deprecated and will be " 

750 "removed in a future release. Please refer to " 

751 ":meth:`_query.Query.scalar_subquery`.", 

752 ) 

753 def as_scalar(self) -> ScalarSelect[Any]: 

754 """Return the full SELECT statement represented by this 

755 :class:`_query.Query`, converted to a scalar subquery. 

756 

757 """ 

758 return self.scalar_subquery() 

759 

760 @overload 

761 def scalar_subquery( 

762 self: Query[Tuple[_MAYBE_ENTITY]], 

763 ) -> ScalarSelect[Any]: ... 

764 

765 @overload 

766 def scalar_subquery( 

767 self: Query[Tuple[_NOT_ENTITY]], 

768 ) -> ScalarSelect[_NOT_ENTITY]: ... 

769 

770 @overload 

771 def scalar_subquery(self) -> ScalarSelect[Any]: ... 

772 

773 def scalar_subquery(self) -> ScalarSelect[Any]: 

774 """Return the full SELECT statement represented by this 

775 :class:`_query.Query`, converted to a scalar subquery. 

776 

777 Analogous to 

778 :meth:`sqlalchemy.sql.expression.SelectBase.scalar_subquery`. 

779 

780 .. versionchanged:: 1.4 The :meth:`_query.Query.scalar_subquery` 

781 method replaces the :meth:`_query.Query.as_scalar` method. 

782 

783 .. seealso:: 

784 

785 :meth:`_sql.Select.scalar_subquery` - v2 comparable method. 

786 

787 """ 

788 

789 return ( 

790 self.enable_eagerloads(False) 

791 ._get_select_statement_only() 

792 .scalar_subquery() 

793 ) 

794 

795 @property 

796 def selectable(self) -> Union[Select[_T], FromStatement[_T], UpdateBase]: 

797 """Return the :class:`_expression.Select` object emitted by this 

798 :class:`_query.Query`. 

799 

800 Used for :func:`_sa.inspect` compatibility, this is equivalent to:: 

801 

802 query.enable_eagerloads(False).with_labels().statement 

803 

804 """ 

805 return self.__clause_element__() 

806 

807 def __clause_element__( 

808 self, 

809 ) -> Union[Select[_T], FromStatement[_T], UpdateBase]: 

810 return ( 

811 self._with_compile_options( 

812 _enable_eagerloads=False, _render_for_subquery=True 

813 ) 

814 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

815 .statement 

816 ) 

817 

818 @overload 

819 def only_return_tuples( 

820 self: Query[_O], value: Literal[True] 

821 ) -> RowReturningQuery[Tuple[_O]]: ... 

822 

823 @overload 

824 def only_return_tuples( 

825 self: Query[_O], value: Literal[False] 

826 ) -> Query[_O]: ... 

827 

828 @_generative 

829 def only_return_tuples(self, value: bool) -> Query[Any]: 

830 """When set to True, the query results will always be a 

831 :class:`.Row` object. 

832 

833 This can change a query that normally returns a single entity 

834 as a scalar to return a :class:`.Row` result in all cases. 

835 

836 .. seealso:: 

837 

838 :meth:`.Query.tuples` - returns tuples, but also at the typing 

839 level will type results as ``Tuple``. 

840 

841 :meth:`_query.Query.is_single_entity` 

842 

843 :meth:`_engine.Result.tuples` - v2 comparable method. 

844 

845 """ 

846 self.load_options += dict(_only_return_tuples=value) 

847 return self 

848 

849 @property 

850 def is_single_entity(self) -> bool: 

851 """Indicates if this :class:`_query.Query` 

852 returns tuples or single entities. 

853 

854 Returns True if this query returns a single entity for each instance 

855 in its result list, and False if this query returns a tuple of entities 

856 for each result. 

857 

858 .. versionadded:: 1.3.11 

859 

860 .. seealso:: 

861 

862 :meth:`_query.Query.only_return_tuples` 

863 

864 """ 

865 return ( 

866 not self.load_options._only_return_tuples 

867 and len(self._raw_columns) == 1 

868 and "parententity" in self._raw_columns[0]._annotations 

869 and isinstance( 

870 self._raw_columns[0]._annotations["parententity"], 

871 ORMColumnsClauseRole, 

872 ) 

873 ) 

874 

875 @_generative 

876 def enable_eagerloads(self, value: bool) -> Self: 

877 """Control whether or not eager joins and subqueries are 

878 rendered. 

879 

880 When set to False, the returned Query will not render 

881 eager joins regardless of :func:`~sqlalchemy.orm.joinedload`, 

882 :func:`~sqlalchemy.orm.subqueryload` options 

883 or mapper-level ``lazy='joined'``/``lazy='subquery'`` 

884 configurations. 

885 

886 This is used primarily when nesting the Query's 

887 statement into a subquery or other 

888 selectable, or when using :meth:`_query.Query.yield_per`. 

889 

890 """ 

891 self._compile_options += {"_enable_eagerloads": value} 

892 return self 

893 

894 @_generative 

895 def _with_compile_options(self, **opt: Any) -> Self: 

896 self._compile_options += opt 

897 return self 

898 

899 @util.became_legacy_20( 

900 ":meth:`_orm.Query.with_labels` and :meth:`_orm.Query.apply_labels`", 

901 alternative="Use set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) " 

902 "instead.", 

903 ) 

904 def with_labels(self) -> Self: 

905 return self.set_label_style( 

906 SelectLabelStyle.LABEL_STYLE_TABLENAME_PLUS_COL 

907 ) 

908 

909 apply_labels = with_labels 

910 

911 @property 

912 def get_label_style(self) -> SelectLabelStyle: 

913 """ 

914 Retrieve the current label style. 

915 

916 .. versionadded:: 1.4 

917 

918 .. seealso:: 

919 

920 :meth:`_sql.Select.get_label_style` - v2 equivalent method. 

921 

922 """ 

923 return self._label_style 

924 

925 def set_label_style(self, style: SelectLabelStyle) -> Self: 

926 """Apply column labels to the return value of Query.statement. 

927 

928 Indicates that this Query's `statement` accessor should return 

929 a SELECT statement that applies labels to all columns in the 

930 form <tablename>_<columnname>; this is commonly used to 

931 disambiguate columns from multiple tables which have the same 

932 name. 

933 

934 When the `Query` actually issues SQL to load rows, it always 

935 uses column labeling. 

936 

937 .. note:: The :meth:`_query.Query.set_label_style` method *only* applies 

938 the output of :attr:`_query.Query.statement`, and *not* to any of 

939 the result-row invoking systems of :class:`_query.Query` itself, 

940 e.g. 

941 :meth:`_query.Query.first`, :meth:`_query.Query.all`, etc. 

942 To execute 

943 a query using :meth:`_query.Query.set_label_style`, invoke the 

944 :attr:`_query.Query.statement` using :meth:`.Session.execute`:: 

945 

946 result = session.execute( 

947 query.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL).statement 

948 ) 

949 

950 .. versionadded:: 1.4 

951 

952 

953 .. seealso:: 

954 

955 :meth:`_sql.Select.set_label_style` - v2 equivalent method. 

956 

957 """ # noqa 

958 if self._label_style is not style: 

959 self = self._generate() 

960 self._label_style = style 

961 return self 

962 

963 @_generative 

964 def enable_assertions(self, value: bool) -> Self: 

965 """Control whether assertions are generated. 

966 

967 When set to False, the returned Query will 

968 not assert its state before certain operations, 

969 including that LIMIT/OFFSET has not been applied 

970 when filter() is called, no criterion exists 

971 when get() is called, and no "from_statement()" 

972 exists when filter()/order_by()/group_by() etc. 

973 is called. This more permissive mode is used by 

974 custom Query subclasses to specify criterion or 

975 other modifiers outside of the usual usage patterns. 

976 

977 Care should be taken to ensure that the usage 

978 pattern is even possible. A statement applied 

979 by from_statement() will override any criterion 

980 set by filter() or order_by(), for example. 

981 

982 """ 

983 self._enable_assertions = value 

984 return self 

985 

986 @property 

987 def whereclause(self) -> Optional[ColumnElement[bool]]: 

988 """A readonly attribute which returns the current WHERE criterion for 

989 this Query. 

990 

991 This returned value is a SQL expression construct, or ``None`` if no 

992 criterion has been established. 

993 

994 .. seealso:: 

995 

996 :attr:`_sql.Select.whereclause` - v2 equivalent property. 

997 

998 """ 

999 return BooleanClauseList._construct_for_whereclause( 

1000 self._where_criteria 

1001 ) 

1002 

1003 @_generative 

1004 def _with_current_path(self, path: PathRegistry) -> Self: 

1005 """indicate that this query applies to objects loaded 

1006 within a certain path. 

1007 

1008 Used by deferred loaders (see strategies.py) which transfer 

1009 query options from an originating query to a newly generated 

1010 query intended for the deferred load. 

1011 

1012 """ 

1013 self._compile_options += {"_current_path": path} 

1014 return self 

1015 

1016 @_generative 

1017 def yield_per(self, count: int) -> Self: 

1018 r"""Yield only ``count`` rows at a time. 

1019 

1020 The purpose of this method is when fetching very large result sets 

1021 (> 10K rows), to batch results in sub-collections and yield them 

1022 out partially, so that the Python interpreter doesn't need to declare 

1023 very large areas of memory which is both time consuming and leads 

1024 to excessive memory use. The performance from fetching hundreds of 

1025 thousands of rows can often double when a suitable yield-per setting 

1026 (e.g. approximately 1000) is used, even with DBAPIs that buffer 

1027 rows (which are most). 

1028 

1029 As of SQLAlchemy 1.4, the :meth:`_orm.Query.yield_per` method is 

1030 equivalent to using the ``yield_per`` execution option at the ORM 

1031 level. See the section :ref:`orm_queryguide_yield_per` for further 

1032 background on this option. 

1033 

1034 .. seealso:: 

1035 

1036 :ref:`orm_queryguide_yield_per` 

1037 

1038 """ 

1039 self.load_options += {"_yield_per": count} 

1040 return self 

1041 

1042 @util.became_legacy_20( 

1043 ":meth:`_orm.Query.get`", 

1044 alternative="The method is now available as :meth:`_orm.Session.get`", 

1045 ) 

1046 def get(self, ident: _PKIdentityArgument) -> Optional[_T]: 

1047 """Return an instance based on the given primary key identifier, 

1048 or ``None`` if not found. 

1049 

1050 E.g.:: 

1051 

1052 my_user = session.query(User).get(5) 

1053 

1054 some_object = session.query(VersionedFoo).get((5, 10)) 

1055 

1056 some_object = session.query(VersionedFoo).get({"id": 5, "version_id": 10}) 

1057 

1058 :meth:`_query.Query.get` is special in that it provides direct 

1059 access to the identity map of the owning :class:`.Session`. 

1060 If the given primary key identifier is present 

1061 in the local identity map, the object is returned 

1062 directly from this collection and no SQL is emitted, 

1063 unless the object has been marked fully expired. 

1064 If not present, 

1065 a SELECT is performed in order to locate the object. 

1066 

1067 :meth:`_query.Query.get` also will perform a check if 

1068 the object is present in the identity map and 

1069 marked as expired - a SELECT 

1070 is emitted to refresh the object as well as to 

1071 ensure that the row is still present. 

1072 If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised. 

1073 

1074 :meth:`_query.Query.get` is only used to return a single 

1075 mapped instance, not multiple instances or 

1076 individual column constructs, and strictly 

1077 on a single primary key value. The originating 

1078 :class:`_query.Query` must be constructed in this way, 

1079 i.e. against a single mapped entity, 

1080 with no additional filtering criterion. Loading 

1081 options via :meth:`_query.Query.options` may be applied 

1082 however, and will be used if the object is not 

1083 yet locally present. 

1084 

1085 :param ident: A scalar, tuple, or dictionary representing the 

1086 primary key. For a composite (e.g. multiple column) primary key, 

1087 a tuple or dictionary should be passed. 

1088 

1089 For a single-column primary key, the scalar calling form is typically 

1090 the most expedient. If the primary key of a row is the value "5", 

1091 the call looks like:: 

1092 

1093 my_object = query.get(5) 

1094 

1095 The tuple form contains primary key values typically in 

1096 the order in which they correspond to the mapped 

1097 :class:`_schema.Table` 

1098 object's primary key columns, or if the 

1099 :paramref:`_orm.Mapper.primary_key` configuration parameter were 

1100 used, in 

1101 the order used for that parameter. For example, if the primary key 

1102 of a row is represented by the integer 

1103 digits "5, 10" the call would look like:: 

1104 

1105 my_object = query.get((5, 10)) 

1106 

1107 The dictionary form should include as keys the mapped attribute names 

1108 corresponding to each element of the primary key. If the mapped class 

1109 has the attributes ``id``, ``version_id`` as the attributes which 

1110 store the object's primary key value, the call would look like:: 

1111 

1112 my_object = query.get({"id": 5, "version_id": 10}) 

1113 

1114 .. versionadded:: 1.3 the :meth:`_query.Query.get` 

1115 method now optionally 

1116 accepts a dictionary of attribute names to values in order to 

1117 indicate a primary key identifier. 

1118 

1119 

1120 :return: The object instance, or ``None``. 

1121 

1122 """ # noqa: E501 

1123 self._no_criterion_assertion("get", order_by=False, distinct=False) 

1124 

1125 # we still implement _get_impl() so that baked query can override 

1126 # it 

1127 return self._get_impl(ident, loading.load_on_pk_identity) 

1128 

1129 def _get_impl( 

1130 self, 

1131 primary_key_identity: _PKIdentityArgument, 

1132 db_load_fn: Callable[..., Any], 

1133 identity_token: Optional[Any] = None, 

1134 ) -> Optional[Any]: 

1135 mapper = self._only_full_mapper_zero("get") 

1136 return self.session._get_impl( 

1137 mapper, 

1138 primary_key_identity, 

1139 db_load_fn, 

1140 populate_existing=self.load_options._populate_existing, 

1141 with_for_update=self._for_update_arg, 

1142 options=self._with_options, 

1143 identity_token=identity_token, 

1144 execution_options=self._execution_options, 

1145 ) 

1146 

1147 @property 

1148 def lazy_loaded_from(self) -> Optional[InstanceState[Any]]: 

1149 """An :class:`.InstanceState` that is using this :class:`_query.Query` 

1150 for a lazy load operation. 

1151 

1152 .. deprecated:: 1.4 This attribute should be viewed via the 

1153 :attr:`.ORMExecuteState.lazy_loaded_from` attribute, within 

1154 the context of the :meth:`.SessionEvents.do_orm_execute` 

1155 event. 

1156 

1157 .. seealso:: 

1158 

1159 :attr:`.ORMExecuteState.lazy_loaded_from` 

1160 

1161 """ 

1162 return self.load_options._lazy_loaded_from # type: ignore 

1163 

1164 @property 

1165 def _current_path(self) -> PathRegistry: 

1166 return self._compile_options._current_path # type: ignore 

1167 

1168 @_generative 

1169 def correlate( 

1170 self, 

1171 *fromclauses: Union[Literal[None, False], _FromClauseArgument], 

1172 ) -> Self: 

1173 """Return a :class:`.Query` construct which will correlate the given 

1174 FROM clauses to that of an enclosing :class:`.Query` or 

1175 :func:`~.expression.select`. 

1176 

1177 The method here accepts mapped classes, :func:`.aliased` constructs, 

1178 and :class:`_orm.Mapper` constructs as arguments, which are resolved 

1179 into expression constructs, in addition to appropriate expression 

1180 constructs. 

1181 

1182 The correlation arguments are ultimately passed to 

1183 :meth:`_expression.Select.correlate` 

1184 after coercion to expression constructs. 

1185 

1186 The correlation arguments take effect in such cases 

1187 as when :meth:`_query.Query.from_self` is used, or when 

1188 a subquery as returned by :meth:`_query.Query.subquery` is 

1189 embedded in another :func:`_expression.select` construct. 

1190 

1191 .. seealso:: 

1192 

1193 :meth:`_sql.Select.correlate` - v2 equivalent method. 

1194 

1195 """ 

1196 

1197 self._auto_correlate = False 

1198 if fromclauses and fromclauses[0] in {None, False}: 

1199 self._correlate = () 

1200 else: 

1201 self._correlate = self._correlate + tuple( 

1202 coercions.expect(roles.FromClauseRole, f) for f in fromclauses 

1203 ) 

1204 return self 

1205 

1206 @_generative 

1207 def autoflush(self, setting: bool) -> Self: 

1208 """Return a Query with a specific 'autoflush' setting. 

1209 

1210 As of SQLAlchemy 1.4, the :meth:`_orm.Query.autoflush` method 

1211 is equivalent to using the ``autoflush`` execution option at the 

1212 ORM level. See the section :ref:`orm_queryguide_autoflush` for 

1213 further background on this option. 

1214 

1215 """ 

1216 self.load_options += {"_autoflush": setting} 

1217 return self 

1218 

1219 @_generative 

1220 def populate_existing(self) -> Self: 

1221 """Return a :class:`_query.Query` 

1222 that will expire and refresh all instances 

1223 as they are loaded, or reused from the current :class:`.Session`. 

1224 

1225 As of SQLAlchemy 1.4, the :meth:`_orm.Query.populate_existing` method 

1226 is equivalent to using the ``populate_existing`` execution option at 

1227 the ORM level. See the section :ref:`orm_queryguide_populate_existing` 

1228 for further background on this option. 

1229 

1230 """ 

1231 self.load_options += {"_populate_existing": True} 

1232 return self 

1233 

1234 @_generative 

1235 def _with_invoke_all_eagers(self, value: bool) -> Self: 

1236 """Set the 'invoke all eagers' flag which causes joined- and 

1237 subquery loaders to traverse into already-loaded related objects 

1238 and collections. 

1239 

1240 Default is that of :attr:`_query.Query._invoke_all_eagers`. 

1241 

1242 """ 

1243 self.load_options += {"_invoke_all_eagers": value} 

1244 return self 

1245 

1246 @util.became_legacy_20( 

1247 ":meth:`_orm.Query.with_parent`", 

1248 alternative="Use the :func:`_orm.with_parent` standalone construct.", 

1249 ) 

1250 @util.preload_module("sqlalchemy.orm.relationships") 

1251 def with_parent( 

1252 self, 

1253 instance: object, 

1254 property: Optional[ # noqa: A002 

1255 attributes.QueryableAttribute[Any] 

1256 ] = None, 

1257 from_entity: Optional[_ExternalEntityType[Any]] = None, 

1258 ) -> Self: 

1259 """Add filtering criterion that relates the given instance 

1260 to a child object or collection, using its attribute state 

1261 as well as an established :func:`_orm.relationship()` 

1262 configuration. 

1263 

1264 The method uses the :func:`.with_parent` function to generate 

1265 the clause, the result of which is passed to 

1266 :meth:`_query.Query.filter`. 

1267 

1268 Parameters are the same as :func:`.with_parent`, with the exception 

1269 that the given property can be None, in which case a search is 

1270 performed against this :class:`_query.Query` object's target mapper. 

1271 

1272 :param instance: 

1273 An instance which has some :func:`_orm.relationship`. 

1274 

1275 :param property: 

1276 Class bound attribute which indicates 

1277 what relationship from the instance should be used to reconcile the 

1278 parent/child relationship. 

1279 

1280 :param from_entity: 

1281 Entity in which to consider as the left side. This defaults to the 

1282 "zero" entity of the :class:`_query.Query` itself. 

1283 

1284 """ 

1285 relationships = util.preloaded.orm_relationships 

1286 

1287 if from_entity: 

1288 entity_zero = inspect(from_entity) 

1289 else: 

1290 entity_zero = _legacy_filter_by_entity_zero(self) 

1291 if property is None: 

1292 # TODO: deprecate, property has to be supplied 

1293 mapper = object_mapper(instance) 

1294 

1295 for prop in mapper.iterate_properties: 

1296 if ( 

1297 isinstance(prop, relationships.RelationshipProperty) 

1298 and prop.mapper is entity_zero.mapper # type: ignore 

1299 ): 

1300 property = prop # type: ignore # noqa: A001 

1301 break 

1302 else: 

1303 raise sa_exc.InvalidRequestError( 

1304 "Could not locate a property which relates instances " 

1305 "of class '%s' to instances of class '%s'" 

1306 % ( 

1307 entity_zero.mapper.class_.__name__, # type: ignore 

1308 instance.__class__.__name__, 

1309 ) 

1310 ) 

1311 

1312 return self.filter( 

1313 with_parent( 

1314 instance, 

1315 property, # type: ignore 

1316 entity_zero.entity, # type: ignore 

1317 ) 

1318 ) 

1319 

1320 @_generative 

1321 def add_entity( 

1322 self, 

1323 entity: _EntityType[Any], 

1324 alias: Optional[Union[Alias, Subquery]] = None, 

1325 ) -> Query[Any]: 

1326 """add a mapped entity to the list of result columns 

1327 to be returned. 

1328 

1329 .. seealso:: 

1330 

1331 :meth:`_sql.Select.add_columns` - v2 comparable method. 

1332 """ 

1333 

1334 if alias is not None: 

1335 # TODO: deprecate 

1336 entity = AliasedClass(entity, alias) 

1337 

1338 self._raw_columns = list(self._raw_columns) 

1339 

1340 self._raw_columns.append( 

1341 coercions.expect( 

1342 roles.ColumnsClauseRole, entity, apply_propagate_attrs=self 

1343 ) 

1344 ) 

1345 return self 

1346 

1347 @_generative 

1348 def with_session(self, session: Session) -> Self: 

1349 """Return a :class:`_query.Query` that will use the given 

1350 :class:`.Session`. 

1351 

1352 While the :class:`_query.Query` 

1353 object is normally instantiated using the 

1354 :meth:`.Session.query` method, it is legal to build the 

1355 :class:`_query.Query` 

1356 directly without necessarily using a :class:`.Session`. Such a 

1357 :class:`_query.Query` object, or any :class:`_query.Query` 

1358 already associated 

1359 with a different :class:`.Session`, can produce a new 

1360 :class:`_query.Query` 

1361 object associated with a target session using this method:: 

1362 

1363 from sqlalchemy.orm import Query 

1364 

1365 query = Query([MyClass]).filter(MyClass.id == 5) 

1366 

1367 result = query.with_session(my_session).one() 

1368 

1369 """ 

1370 

1371 self.session = session 

1372 return self 

1373 

1374 def _legacy_from_self( 

1375 self, *entities: _ColumnsClauseArgument[Any] 

1376 ) -> Self: 

1377 # used for query.count() as well as for the same 

1378 # function in BakedQuery, as well as some old tests in test_baked.py. 

1379 

1380 fromclause = ( 

1381 self.set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

1382 .correlate(None) 

1383 .subquery() 

1384 ._anonymous_fromclause() 

1385 ) 

1386 

1387 q = self._from_selectable(fromclause) 

1388 

1389 if entities: 

1390 q._set_entities(entities) 

1391 return q 

1392 

1393 @_generative 

1394 def _set_enable_single_crit(self, val: bool) -> Self: 

1395 self._compile_options += {"_enable_single_crit": val} 

1396 return self 

1397 

1398 @_generative 

1399 def _from_selectable( 

1400 self, fromclause: FromClause, set_entity_from: bool = True 

1401 ) -> Self: 

1402 for attr in ( 

1403 "_where_criteria", 

1404 "_order_by_clauses", 

1405 "_group_by_clauses", 

1406 "_limit_clause", 

1407 "_offset_clause", 

1408 "_last_joined_entity", 

1409 "_setup_joins", 

1410 "_memoized_select_entities", 

1411 "_distinct", 

1412 "_distinct_on", 

1413 "_having_criteria", 

1414 "_prefixes", 

1415 "_suffixes", 

1416 ): 

1417 self.__dict__.pop(attr, None) 

1418 self._set_select_from([fromclause], set_entity_from) 

1419 self._compile_options += { 

1420 "_enable_single_crit": False, 

1421 } 

1422 

1423 return self 

1424 

1425 @util.deprecated( 

1426 "1.4", 

1427 ":meth:`_query.Query.values` " 

1428 "is deprecated and will be removed in a " 

1429 "future release. Please use :meth:`_query.Query.with_entities`", 

1430 ) 

1431 def values(self, *columns: _ColumnsClauseArgument[Any]) -> Iterable[Any]: 

1432 """Return an iterator yielding result tuples corresponding 

1433 to the given list of columns 

1434 

1435 """ 

1436 return self._values_no_warn(*columns) 

1437 

1438 _values = values 

1439 

1440 def _values_no_warn( 

1441 self, *columns: _ColumnsClauseArgument[Any] 

1442 ) -> Iterable[Any]: 

1443 if not columns: 

1444 return iter(()) 

1445 q = self._clone().enable_eagerloads(False) 

1446 q._set_entities(columns) 

1447 if not q.load_options._yield_per: 

1448 q.load_options += {"_yield_per": 10} 

1449 return iter(q) 

1450 

1451 @util.deprecated( 

1452 "1.4", 

1453 ":meth:`_query.Query.value` " 

1454 "is deprecated and will be removed in a " 

1455 "future release. Please use :meth:`_query.Query.with_entities` " 

1456 "in combination with :meth:`_query.Query.scalar`", 

1457 ) 

1458 def value(self, column: _ColumnExpressionArgument[Any]) -> Any: 

1459 """Return a scalar result corresponding to the given 

1460 column expression. 

1461 

1462 """ 

1463 try: 

1464 return next(self._values_no_warn(column))[0] # type: ignore 

1465 except StopIteration: 

1466 return None 

1467 

1468 @overload 

1469 def with_entities(self, _entity: _EntityType[_O]) -> Query[_O]: ... 

1470 

1471 @overload 

1472 def with_entities( 

1473 self, 

1474 _colexpr: roles.TypedColumnsClauseRole[_T], 

1475 ) -> RowReturningQuery[Tuple[_T]]: ... 

1476 

1477 # START OVERLOADED FUNCTIONS self.with_entities RowReturningQuery 2-8 

1478 

1479 # code within this block is **programmatically, 

1480 # statically generated** by tools/generate_tuple_map_overloads.py 

1481 

1482 @overload 

1483 def with_entities( 

1484 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1] 

1485 ) -> RowReturningQuery[Tuple[_T0, _T1]]: ... 

1486 

1487 @overload 

1488 def with_entities( 

1489 self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2] 

1490 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2]]: ... 

1491 

1492 @overload 

1493 def with_entities( 

1494 self, 

1495 __ent0: _TCCA[_T0], 

1496 __ent1: _TCCA[_T1], 

1497 __ent2: _TCCA[_T2], 

1498 __ent3: _TCCA[_T3], 

1499 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3]]: ... 

1500 

1501 @overload 

1502 def with_entities( 

1503 self, 

1504 __ent0: _TCCA[_T0], 

1505 __ent1: _TCCA[_T1], 

1506 __ent2: _TCCA[_T2], 

1507 __ent3: _TCCA[_T3], 

1508 __ent4: _TCCA[_T4], 

1509 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4]]: ... 

1510 

1511 @overload 

1512 def with_entities( 

1513 self, 

1514 __ent0: _TCCA[_T0], 

1515 __ent1: _TCCA[_T1], 

1516 __ent2: _TCCA[_T2], 

1517 __ent3: _TCCA[_T3], 

1518 __ent4: _TCCA[_T4], 

1519 __ent5: _TCCA[_T5], 

1520 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ... 

1521 

1522 @overload 

1523 def with_entities( 

1524 self, 

1525 __ent0: _TCCA[_T0], 

1526 __ent1: _TCCA[_T1], 

1527 __ent2: _TCCA[_T2], 

1528 __ent3: _TCCA[_T3], 

1529 __ent4: _TCCA[_T4], 

1530 __ent5: _TCCA[_T5], 

1531 __ent6: _TCCA[_T6], 

1532 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ... 

1533 

1534 @overload 

1535 def with_entities( 

1536 self, 

1537 __ent0: _TCCA[_T0], 

1538 __ent1: _TCCA[_T1], 

1539 __ent2: _TCCA[_T2], 

1540 __ent3: _TCCA[_T3], 

1541 __ent4: _TCCA[_T4], 

1542 __ent5: _TCCA[_T5], 

1543 __ent6: _TCCA[_T6], 

1544 __ent7: _TCCA[_T7], 

1545 ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ... 

1546 

1547 # END OVERLOADED FUNCTIONS self.with_entities 

1548 

1549 @overload 

1550 def with_entities( 

1551 self, *entities: _ColumnsClauseArgument[Any] 

1552 ) -> Query[Any]: ... 

1553 

1554 @_generative 

1555 def with_entities( 

1556 self, *entities: _ColumnsClauseArgument[Any], **__kw: Any 

1557 ) -> Query[Any]: 

1558 r"""Return a new :class:`_query.Query` 

1559 replacing the SELECT list with the 

1560 given entities. 

1561 

1562 e.g.:: 

1563 

1564 # Users, filtered on some arbitrary criterion 

1565 # and then ordered by related email address 

1566 q = ( 

1567 session.query(User) 

1568 .join(User.address) 

1569 .filter(User.name.like("%ed%")) 

1570 .order_by(Address.email) 

1571 ) 

1572 

1573 # given *only* User.id==5, Address.email, and 'q', what 

1574 # would the *next* User in the result be ? 

1575 subq = ( 

1576 q.with_entities(Address.email) 

1577 .order_by(None) 

1578 .filter(User.id == 5) 

1579 .subquery() 

1580 ) 

1581 q = q.join((subq, subq.c.email < Address.email)).limit(1) 

1582 

1583 .. seealso:: 

1584 

1585 :meth:`_sql.Select.with_only_columns` - v2 comparable method. 

1586 """ 

1587 if __kw: 

1588 raise _no_kw() 

1589 

1590 # Query has all the same fields as Select for this operation 

1591 # this could in theory be based on a protocol but not sure if it's 

1592 # worth it 

1593 _MemoizedSelectEntities._generate_for_statement(self) # type: ignore 

1594 self._set_entities(entities) 

1595 return self 

1596 

1597 @_generative 

1598 def add_columns( 

1599 self, *column: _ColumnExpressionArgument[Any] 

1600 ) -> Query[Any]: 

1601 """Add one or more column expressions to the list 

1602 of result columns to be returned. 

1603 

1604 .. seealso:: 

1605 

1606 :meth:`_sql.Select.add_columns` - v2 comparable method. 

1607 """ 

1608 

1609 self._raw_columns = list(self._raw_columns) 

1610 

1611 self._raw_columns.extend( 

1612 coercions.expect( 

1613 roles.ColumnsClauseRole, 

1614 c, 

1615 apply_propagate_attrs=self, 

1616 post_inspect=True, 

1617 ) 

1618 for c in column 

1619 ) 

1620 return self 

1621 

1622 @util.deprecated( 

1623 "1.4", 

1624 ":meth:`_query.Query.add_column` " 

1625 "is deprecated and will be removed in a " 

1626 "future release. Please use :meth:`_query.Query.add_columns`", 

1627 ) 

1628 def add_column(self, column: _ColumnExpressionArgument[Any]) -> Query[Any]: 

1629 """Add a column expression to the list of result columns to be 

1630 returned. 

1631 

1632 """ 

1633 return self.add_columns(column) 

1634 

1635 @_generative 

1636 def options(self, *args: ExecutableOption) -> Self: 

1637 """Return a new :class:`_query.Query` object, 

1638 applying the given list of 

1639 mapper options. 

1640 

1641 Most supplied options regard changing how column- and 

1642 relationship-mapped attributes are loaded. 

1643 

1644 .. seealso:: 

1645 

1646 :ref:`loading_columns` 

1647 

1648 :ref:`relationship_loader_options` 

1649 

1650 """ 

1651 

1652 opts = tuple(util.flatten_iterator(args)) 

1653 if self._compile_options._current_path: 

1654 # opting for lower method overhead for the checks 

1655 for opt in opts: 

1656 if not opt._is_core and opt._is_legacy_option: # type: ignore 

1657 opt.process_query_conditionally(self) # type: ignore 

1658 else: 

1659 for opt in opts: 

1660 if not opt._is_core and opt._is_legacy_option: # type: ignore 

1661 opt.process_query(self) # type: ignore 

1662 

1663 self._with_options += opts 

1664 return self 

1665 

1666 def with_transformation( 

1667 self, fn: Callable[[Query[Any]], Query[Any]] 

1668 ) -> Query[Any]: 

1669 """Return a new :class:`_query.Query` object transformed by 

1670 the given function. 

1671 

1672 E.g.:: 

1673 

1674 def filter_something(criterion): 

1675 def transform(q): 

1676 return q.filter(criterion) 

1677 

1678 return transform 

1679 

1680 

1681 q = q.with_transformation(filter_something(x == 5)) 

1682 

1683 This allows ad-hoc recipes to be created for :class:`_query.Query` 

1684 objects. 

1685 

1686 """ 

1687 return fn(self) 

1688 

1689 def get_execution_options(self) -> _ImmutableExecuteOptions: 

1690 """Get the non-SQL options which will take effect during execution. 

1691 

1692 .. versionadded:: 1.3 

1693 

1694 .. seealso:: 

1695 

1696 :meth:`_query.Query.execution_options` 

1697 

1698 :meth:`_sql.Select.get_execution_options` - v2 comparable method. 

1699 

1700 """ 

1701 return self._execution_options 

1702 

1703 @overload 

1704 def execution_options( 

1705 self, 

1706 *, 

1707 compiled_cache: Optional[CompiledCacheType] = ..., 

1708 logging_token: str = ..., 

1709 isolation_level: IsolationLevel = ..., 

1710 no_parameters: bool = False, 

1711 stream_results: bool = False, 

1712 max_row_buffer: int = ..., 

1713 yield_per: int = ..., 

1714 insertmanyvalues_page_size: int = ..., 

1715 schema_translate_map: Optional[SchemaTranslateMapType] = ..., 

1716 populate_existing: bool = False, 

1717 autoflush: bool = False, 

1718 preserve_rowcount: bool = False, 

1719 **opt: Any, 

1720 ) -> Self: ... 

1721 

1722 @overload 

1723 def execution_options(self, **opt: Any) -> Self: ... 

1724 

1725 @_generative 

1726 def execution_options(self, **kwargs: Any) -> Self: 

1727 """Set non-SQL options which take effect during execution. 

1728 

1729 Options allowed here include all of those accepted by 

1730 :meth:`_engine.Connection.execution_options`, as well as a series 

1731 of ORM specific options: 

1732 

1733 ``populate_existing=True`` - equivalent to using 

1734 :meth:`_orm.Query.populate_existing` 

1735 

1736 ``autoflush=True|False`` - equivalent to using 

1737 :meth:`_orm.Query.autoflush` 

1738 

1739 ``yield_per=<value>`` - equivalent to using 

1740 :meth:`_orm.Query.yield_per` 

1741 

1742 Note that the ``stream_results`` execution option is enabled 

1743 automatically if the :meth:`~sqlalchemy.orm.query.Query.yield_per()` 

1744 method or execution option is used. 

1745 

1746 .. versionadded:: 1.4 - added ORM options to 

1747 :meth:`_orm.Query.execution_options` 

1748 

1749 The execution options may also be specified on a per execution basis 

1750 when using :term:`2.0 style` queries via the 

1751 :paramref:`_orm.Session.execution_options` parameter. 

1752 

1753 .. warning:: The 

1754 :paramref:`_engine.Connection.execution_options.stream_results` 

1755 parameter should not be used at the level of individual ORM 

1756 statement executions, as the :class:`_orm.Session` will not track 

1757 objects from different schema translate maps within a single 

1758 session. For multiple schema translate maps within the scope of a 

1759 single :class:`_orm.Session`, see :ref:`examples_sharding`. 

1760 

1761 

1762 .. seealso:: 

1763 

1764 :ref:`engine_stream_results` 

1765 

1766 :meth:`_query.Query.get_execution_options` 

1767 

1768 :meth:`_sql.Select.execution_options` - v2 equivalent method. 

1769 

1770 """ 

1771 self._execution_options = self._execution_options.union(kwargs) 

1772 return self 

1773 

1774 @_generative 

1775 def with_for_update( 

1776 self, 

1777 *, 

1778 nowait: bool = False, 

1779 read: bool = False, 

1780 of: Optional[_ForUpdateOfArgument] = None, 

1781 skip_locked: bool = False, 

1782 key_share: bool = False, 

1783 ) -> Self: 

1784 """return a new :class:`_query.Query` 

1785 with the specified options for the 

1786 ``FOR UPDATE`` clause. 

1787 

1788 The behavior of this method is identical to that of 

1789 :meth:`_expression.GenerativeSelect.with_for_update`. 

1790 When called with no arguments, 

1791 the resulting ``SELECT`` statement will have a ``FOR UPDATE`` clause 

1792 appended. When additional arguments are specified, backend-specific 

1793 options such as ``FOR UPDATE NOWAIT`` or ``LOCK IN SHARE MODE`` 

1794 can take effect. 

1795 

1796 E.g.:: 

1797 

1798 q = ( 

1799 sess.query(User) 

1800 .populate_existing() 

1801 .with_for_update(nowait=True, of=User) 

1802 ) 

1803 

1804 The above query on a PostgreSQL backend will render like: 

1805 

1806 .. sourcecode:: sql 

1807 

1808 SELECT users.id AS users_id FROM users FOR UPDATE OF users NOWAIT 

1809 

1810 .. warning:: 

1811 

1812 Using ``with_for_update`` in the context of eager loading 

1813 relationships is not officially supported or recommended by 

1814 SQLAlchemy and may not work with certain queries on various 

1815 database backends. When ``with_for_update`` is successfully used 

1816 with a query that involves :func:`_orm.joinedload`, SQLAlchemy will 

1817 attempt to emit SQL that locks all involved tables. 

1818 

1819 .. note:: It is generally a good idea to combine the use of the 

1820 :meth:`_orm.Query.populate_existing` method when using the 

1821 :meth:`_orm.Query.with_for_update` method. The purpose of 

1822 :meth:`_orm.Query.populate_existing` is to force all the data read 

1823 from the SELECT to be populated into the ORM objects returned, 

1824 even if these objects are already in the :term:`identity map`. 

1825 

1826 .. seealso:: 

1827 

1828 :meth:`_expression.GenerativeSelect.with_for_update` 

1829 - Core level method with 

1830 full argument and behavioral description. 

1831 

1832 :meth:`_orm.Query.populate_existing` - overwrites attributes of 

1833 objects already loaded in the identity map. 

1834 

1835 """ # noqa: E501 

1836 

1837 self._for_update_arg = ForUpdateArg( 

1838 read=read, 

1839 nowait=nowait, 

1840 of=of, 

1841 skip_locked=skip_locked, 

1842 key_share=key_share, 

1843 ) 

1844 return self 

1845 

1846 @_generative 

1847 def params( 

1848 self, __params: Optional[Dict[str, Any]] = None, **kw: Any 

1849 ) -> Self: 

1850 r"""Add values for bind parameters which may have been 

1851 specified in filter(). 

1852 

1853 Parameters may be specified using \**kwargs, or optionally a single 

1854 dictionary as the first positional argument. The reason for both is 

1855 that \**kwargs is convenient, however some parameter dictionaries 

1856 contain unicode keys in which case \**kwargs cannot be used. 

1857 

1858 """ 

1859 if __params: 

1860 kw.update(__params) 

1861 self._params = self._params.union(kw) 

1862 return self 

1863 

1864 def where(self, *criterion: _ColumnExpressionArgument[bool]) -> Self: 

1865 """A synonym for :meth:`.Query.filter`. 

1866 

1867 .. versionadded:: 1.4 

1868 

1869 .. seealso:: 

1870 

1871 :meth:`_sql.Select.where` - v2 equivalent method. 

1872 

1873 """ 

1874 return self.filter(*criterion) 

1875 

1876 @_generative 

1877 @_assertions(_no_statement_condition, _no_limit_offset) 

1878 def filter(self, *criterion: _ColumnExpressionArgument[bool]) -> Self: 

1879 r"""Apply the given filtering criterion to a copy 

1880 of this :class:`_query.Query`, using SQL expressions. 

1881 

1882 e.g.:: 

1883 

1884 session.query(MyClass).filter(MyClass.name == "some name") 

1885 

1886 Multiple criteria may be specified as comma separated; the effect 

1887 is that they will be joined together using the :func:`.and_` 

1888 function:: 

1889 

1890 session.query(MyClass).filter(MyClass.name == "some name", MyClass.id > 5) 

1891 

1892 The criterion is any SQL expression object applicable to the 

1893 WHERE clause of a select. String expressions are coerced 

1894 into SQL expression constructs via the :func:`_expression.text` 

1895 construct. 

1896 

1897 .. seealso:: 

1898 

1899 :meth:`_query.Query.filter_by` - filter on keyword expressions. 

1900 

1901 :meth:`_sql.Select.where` - v2 equivalent method. 

1902 

1903 """ # noqa: E501 

1904 for crit in list(criterion): 

1905 crit = coercions.expect( 

1906 roles.WhereHavingRole, crit, apply_propagate_attrs=self 

1907 ) 

1908 

1909 self._where_criteria += (crit,) 

1910 return self 

1911 

1912 @util.memoized_property 

1913 def _last_joined_entity( 

1914 self, 

1915 ) -> Optional[Union[_InternalEntityType[Any], _JoinTargetElement]]: 

1916 if self._setup_joins: 

1917 return _determine_last_joined_entity( 

1918 self._setup_joins, 

1919 ) 

1920 else: 

1921 return None 

1922 

1923 def _filter_by_zero(self) -> Any: 

1924 """for the filter_by() method, return the target entity for which 

1925 we will attempt to derive an expression from based on string name. 

1926 

1927 """ 

1928 

1929 if self._setup_joins: 

1930 _last_joined_entity = self._last_joined_entity 

1931 if _last_joined_entity is not None: 

1932 return _last_joined_entity 

1933 

1934 # discussion related to #7239 

1935 # special check determines if we should try to derive attributes 

1936 # for filter_by() from the "from object", i.e., if the user 

1937 # called query.select_from(some selectable).filter_by(some_attr=value). 

1938 # We don't want to do that in the case that methods like 

1939 # from_self(), select_entity_from(), or a set op like union() were 

1940 # called; while these methods also place a 

1941 # selectable in the _from_obj collection, they also set up 

1942 # the _set_base_alias boolean which turns on the whole "adapt the 

1943 # entity to this selectable" thing, meaning the query still continues 

1944 # to construct itself in terms of the lead entity that was passed 

1945 # to query(), e.g. query(User).from_self() is still in terms of User, 

1946 # and not the subquery that from_self() created. This feature of 

1947 # "implicitly adapt all occurrences of entity X to some arbitrary 

1948 # subquery" is the main thing I am trying to do away with in 2.0 as 

1949 # users should now used aliased() for that, but I can't entirely get 

1950 # rid of it due to query.union() and other set ops relying upon it. 

1951 # 

1952 # compare this to the base Select()._filter_by_zero() which can 

1953 # just return self._from_obj[0] if present, because there is no 

1954 # "_set_base_alias" feature. 

1955 # 

1956 # IOW, this conditional essentially detects if 

1957 # "select_from(some_selectable)" has been called, as opposed to 

1958 # "select_entity_from()", "from_self()" 

1959 # or "union() / some_set_op()". 

1960 if self._from_obj and not self._compile_options._set_base_alias: 

1961 return self._from_obj[0] 

1962 

1963 return self._raw_columns[0] 

1964 

1965 def filter_by(self, **kwargs: Any) -> Self: 

1966 r"""Apply the given filtering criterion to a copy 

1967 of this :class:`_query.Query`, using keyword expressions. 

1968 

1969 e.g.:: 

1970 

1971 session.query(MyClass).filter_by(name="some name") 

1972 

1973 Multiple criteria may be specified as comma separated; the effect 

1974 is that they will be joined together using the :func:`.and_` 

1975 function:: 

1976 

1977 session.query(MyClass).filter_by(name="some name", id=5) 

1978 

1979 The keyword expressions are extracted from the primary 

1980 entity of the query, or the last entity that was the 

1981 target of a call to :meth:`_query.Query.join`. 

1982 

1983 .. seealso:: 

1984 

1985 :meth:`_query.Query.filter` - filter on SQL expressions. 

1986 

1987 :meth:`_sql.Select.filter_by` - v2 comparable method. 

1988 

1989 """ 

1990 from_entity = self._filter_by_zero() 

1991 

1992 clauses = [ 

1993 _entity_namespace_key(from_entity, key) == value 

1994 for key, value in kwargs.items() 

1995 ] 

1996 return self.filter(*clauses) 

1997 

1998 @_generative 

1999 def order_by( 

2000 self, 

2001 __first: Union[ 

2002 Literal[None, False, _NoArg.NO_ARG], 

2003 _ColumnExpressionOrStrLabelArgument[Any], 

2004 ] = _NoArg.NO_ARG, 

2005 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

2006 ) -> Self: 

2007 """Apply one or more ORDER BY criteria to the query and return 

2008 the newly resulting :class:`_query.Query`. 

2009 

2010 e.g.:: 

2011 

2012 q = session.query(Entity).order_by(Entity.id, Entity.name) 

2013 

2014 Calling this method multiple times is equivalent to calling it once 

2015 with all the clauses concatenated. All existing ORDER BY criteria may 

2016 be cancelled by passing ``None`` by itself. New ORDER BY criteria may 

2017 then be added by invoking :meth:`_orm.Query.order_by` again, e.g.:: 

2018 

2019 # will erase all ORDER BY and ORDER BY new_col alone 

2020 q = q.order_by(None).order_by(new_col) 

2021 

2022 .. seealso:: 

2023 

2024 These sections describe ORDER BY in terms of :term:`2.0 style` 

2025 invocation but apply to :class:`_orm.Query` as well: 

2026 

2027 :ref:`tutorial_order_by` - in the :ref:`unified_tutorial` 

2028 

2029 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

2030 

2031 :meth:`_sql.Select.order_by` - v2 equivalent method. 

2032 

2033 """ 

2034 

2035 for assertion in (self._no_statement_condition, self._no_limit_offset): 

2036 assertion("order_by") 

2037 

2038 if not clauses and (__first is None or __first is False): 

2039 self._order_by_clauses = () 

2040 elif __first is not _NoArg.NO_ARG: 

2041 criterion = tuple( 

2042 coercions.expect(roles.OrderByRole, clause) 

2043 for clause in (__first,) + clauses 

2044 ) 

2045 self._order_by_clauses += criterion 

2046 

2047 return self 

2048 

2049 @_generative 

2050 def group_by( 

2051 self, 

2052 __first: Union[ 

2053 Literal[None, False, _NoArg.NO_ARG], 

2054 _ColumnExpressionOrStrLabelArgument[Any], 

2055 ] = _NoArg.NO_ARG, 

2056 *clauses: _ColumnExpressionOrStrLabelArgument[Any], 

2057 ) -> Self: 

2058 """Apply one or more GROUP BY criterion to the query and return 

2059 the newly resulting :class:`_query.Query`. 

2060 

2061 All existing GROUP BY settings can be suppressed by 

2062 passing ``None`` - this will suppress any GROUP BY configured 

2063 on mappers as well. 

2064 

2065 .. seealso:: 

2066 

2067 These sections describe GROUP BY in terms of :term:`2.0 style` 

2068 invocation but apply to :class:`_orm.Query` as well: 

2069 

2070 :ref:`tutorial_group_by_w_aggregates` - in the 

2071 :ref:`unified_tutorial` 

2072 

2073 :ref:`tutorial_order_by_label` - in the :ref:`unified_tutorial` 

2074 

2075 :meth:`_sql.Select.group_by` - v2 equivalent method. 

2076 

2077 """ 

2078 

2079 for assertion in (self._no_statement_condition, self._no_limit_offset): 

2080 assertion("group_by") 

2081 

2082 if not clauses and (__first is None or __first is False): 

2083 self._group_by_clauses = () 

2084 elif __first is not _NoArg.NO_ARG: 

2085 criterion = tuple( 

2086 coercions.expect(roles.GroupByRole, clause) 

2087 for clause in (__first,) + clauses 

2088 ) 

2089 self._group_by_clauses += criterion 

2090 return self 

2091 

2092 @_generative 

2093 @_assertions(_no_statement_condition, _no_limit_offset) 

2094 def having(self, *having: _ColumnExpressionArgument[bool]) -> Self: 

2095 r"""Apply a HAVING criterion to the query and return the 

2096 newly resulting :class:`_query.Query`. 

2097 

2098 :meth:`_query.Query.having` is used in conjunction with 

2099 :meth:`_query.Query.group_by`. 

2100 

2101 HAVING criterion makes it possible to use filters on aggregate 

2102 functions like COUNT, SUM, AVG, MAX, and MIN, eg.:: 

2103 

2104 q = ( 

2105 session.query(User.id) 

2106 .join(User.addresses) 

2107 .group_by(User.id) 

2108 .having(func.count(Address.id) > 2) 

2109 ) 

2110 

2111 .. seealso:: 

2112 

2113 :meth:`_sql.Select.having` - v2 equivalent method. 

2114 

2115 """ 

2116 

2117 for criterion in having: 

2118 having_criteria = coercions.expect( 

2119 roles.WhereHavingRole, criterion 

2120 ) 

2121 self._having_criteria += (having_criteria,) 

2122 return self 

2123 

2124 def _set_op(self, expr_fn: Any, *q: Query[Any]) -> Self: 

2125 list_of_queries = (self,) + q 

2126 return self._from_selectable(expr_fn(*(list_of_queries)).subquery()) 

2127 

2128 def union(self, *q: Query[Any]) -> Self: 

2129 """Produce a UNION of this Query against one or more queries. 

2130 

2131 e.g.:: 

2132 

2133 q1 = sess.query(SomeClass).filter(SomeClass.foo == "bar") 

2134 q2 = sess.query(SomeClass).filter(SomeClass.bar == "foo") 

2135 

2136 q3 = q1.union(q2) 

2137 

2138 The method accepts multiple Query objects so as to control 

2139 the level of nesting. A series of ``union()`` calls such as:: 

2140 

2141 x.union(y).union(z).all() 

2142 

2143 will nest on each ``union()``, and produces: 

2144 

2145 .. sourcecode:: sql 

2146 

2147 SELECT * FROM (SELECT * FROM (SELECT * FROM X UNION 

2148 SELECT * FROM y) UNION SELECT * FROM Z) 

2149 

2150 Whereas:: 

2151 

2152 x.union(y, z).all() 

2153 

2154 produces: 

2155 

2156 .. sourcecode:: sql 

2157 

2158 SELECT * FROM (SELECT * FROM X UNION SELECT * FROM y UNION 

2159 SELECT * FROM Z) 

2160 

2161 Note that many database backends do not allow ORDER BY to 

2162 be rendered on a query called within UNION, EXCEPT, etc. 

2163 To disable all ORDER BY clauses including those configured 

2164 on mappers, issue ``query.order_by(None)`` - the resulting 

2165 :class:`_query.Query` object will not render ORDER BY within 

2166 its SELECT statement. 

2167 

2168 .. seealso:: 

2169 

2170 :meth:`_sql.Select.union` - v2 equivalent method. 

2171 

2172 """ 

2173 return self._set_op(expression.union, *q) 

2174 

2175 def union_all(self, *q: Query[Any]) -> Self: 

2176 """Produce a UNION ALL of this Query against one or more queries. 

2177 

2178 Works the same way as :meth:`~sqlalchemy.orm.query.Query.union`. See 

2179 that method for usage examples. 

2180 

2181 .. seealso:: 

2182 

2183 :meth:`_sql.Select.union_all` - v2 equivalent method. 

2184 

2185 """ 

2186 return self._set_op(expression.union_all, *q) 

2187 

2188 def intersect(self, *q: Query[Any]) -> Self: 

2189 """Produce an INTERSECT of this Query against one or more queries. 

2190 

2191 Works the same way as :meth:`~sqlalchemy.orm.query.Query.union`. See 

2192 that method for usage examples. 

2193 

2194 .. seealso:: 

2195 

2196 :meth:`_sql.Select.intersect` - v2 equivalent method. 

2197 

2198 """ 

2199 return self._set_op(expression.intersect, *q) 

2200 

2201 def intersect_all(self, *q: Query[Any]) -> Self: 

2202 """Produce an INTERSECT ALL of this Query against one or more queries. 

2203 

2204 Works the same way as :meth:`~sqlalchemy.orm.query.Query.union`. See 

2205 that method for usage examples. 

2206 

2207 .. seealso:: 

2208 

2209 :meth:`_sql.Select.intersect_all` - v2 equivalent method. 

2210 

2211 """ 

2212 return self._set_op(expression.intersect_all, *q) 

2213 

2214 def except_(self, *q: Query[Any]) -> Self: 

2215 """Produce an EXCEPT of this Query against one or more queries. 

2216 

2217 Works the same way as :meth:`~sqlalchemy.orm.query.Query.union`. See 

2218 that method for usage examples. 

2219 

2220 .. seealso:: 

2221 

2222 :meth:`_sql.Select.except_` - v2 equivalent method. 

2223 

2224 """ 

2225 return self._set_op(expression.except_, *q) 

2226 

2227 def except_all(self, *q: Query[Any]) -> Self: 

2228 """Produce an EXCEPT ALL of this Query against one or more queries. 

2229 

2230 Works the same way as :meth:`~sqlalchemy.orm.query.Query.union`. See 

2231 that method for usage examples. 

2232 

2233 .. seealso:: 

2234 

2235 :meth:`_sql.Select.except_all` - v2 equivalent method. 

2236 

2237 """ 

2238 return self._set_op(expression.except_all, *q) 

2239 

2240 @_generative 

2241 @_assertions(_no_statement_condition, _no_limit_offset) 

2242 def join( 

2243 self, 

2244 target: _JoinTargetArgument, 

2245 onclause: Optional[_OnClauseArgument] = None, 

2246 *, 

2247 isouter: bool = False, 

2248 full: bool = False, 

2249 ) -> Self: 

2250 r"""Create a SQL JOIN against this :class:`_query.Query` 

2251 object's criterion 

2252 and apply generatively, returning the newly resulting 

2253 :class:`_query.Query`. 

2254 

2255 **Simple Relationship Joins** 

2256 

2257 Consider a mapping between two classes ``User`` and ``Address``, 

2258 with a relationship ``User.addresses`` representing a collection 

2259 of ``Address`` objects associated with each ``User``. The most 

2260 common usage of :meth:`_query.Query.join` 

2261 is to create a JOIN along this 

2262 relationship, using the ``User.addresses`` attribute as an indicator 

2263 for how this should occur:: 

2264 

2265 q = session.query(User).join(User.addresses) 

2266 

2267 Where above, the call to :meth:`_query.Query.join` along 

2268 ``User.addresses`` will result in SQL approximately equivalent to: 

2269 

2270 .. sourcecode:: sql 

2271 

2272 SELECT user.id, user.name 

2273 FROM user JOIN address ON user.id = address.user_id 

2274 

2275 In the above example we refer to ``User.addresses`` as passed to 

2276 :meth:`_query.Query.join` as the "on clause", that is, it indicates 

2277 how the "ON" portion of the JOIN should be constructed. 

2278 

2279 To construct a chain of joins, multiple :meth:`_query.Query.join` 

2280 calls may be used. The relationship-bound attribute implies both 

2281 the left and right side of the join at once:: 

2282 

2283 q = ( 

2284 session.query(User) 

2285 .join(User.orders) 

2286 .join(Order.items) 

2287 .join(Item.keywords) 

2288 ) 

2289 

2290 .. note:: as seen in the above example, **the order in which each 

2291 call to the join() method occurs is important**. Query would not, 

2292 for example, know how to join correctly if we were to specify 

2293 ``User``, then ``Item``, then ``Order``, in our chain of joins; in 

2294 such a case, depending on the arguments passed, it may raise an 

2295 error that it doesn't know how to join, or it may produce invalid 

2296 SQL in which case the database will raise an error. In correct 

2297 practice, the 

2298 :meth:`_query.Query.join` method is invoked in such a way that lines 

2299 up with how we would want the JOIN clauses in SQL to be 

2300 rendered, and each call should represent a clear link from what 

2301 precedes it. 

2302 

2303 **Joins to a Target Entity or Selectable** 

2304 

2305 A second form of :meth:`_query.Query.join` allows any mapped entity or 

2306 core selectable construct as a target. In this usage, 

2307 :meth:`_query.Query.join` will attempt to create a JOIN along the 

2308 natural foreign key relationship between two entities:: 

2309 

2310 q = session.query(User).join(Address) 

2311 

2312 In the above calling form, :meth:`_query.Query.join` is called upon to 

2313 create the "on clause" automatically for us. This calling form will 

2314 ultimately raise an error if either there are no foreign keys between 

2315 the two entities, or if there are multiple foreign key linkages between 

2316 the target entity and the entity or entities already present on the 

2317 left side such that creating a join requires more information. Note 

2318 that when indicating a join to a target without any ON clause, ORM 

2319 configured relationships are not taken into account. 

2320 

2321 **Joins to a Target with an ON Clause** 

2322 

2323 The third calling form allows both the target entity as well 

2324 as the ON clause to be passed explicitly. A example that includes 

2325 a SQL expression as the ON clause is as follows:: 

2326 

2327 q = session.query(User).join(Address, User.id == Address.user_id) 

2328 

2329 The above form may also use a relationship-bound attribute as the 

2330 ON clause as well:: 

2331 

2332 q = session.query(User).join(Address, User.addresses) 

2333 

2334 The above syntax can be useful for the case where we wish 

2335 to join to an alias of a particular target entity. If we wanted 

2336 to join to ``Address`` twice, it could be achieved using two 

2337 aliases set up using the :func:`~sqlalchemy.orm.aliased` function:: 

2338 

2339 a1 = aliased(Address) 

2340 a2 = aliased(Address) 

2341 

2342 q = ( 

2343 session.query(User) 

2344 .join(a1, User.addresses) 

2345 .join(a2, User.addresses) 

2346 .filter(a1.email_address == "ed@foo.com") 

2347 .filter(a2.email_address == "ed@bar.com") 

2348 ) 

2349 

2350 The relationship-bound calling form can also specify a target entity 

2351 using the :meth:`_orm.PropComparator.of_type` method; a query 

2352 equivalent to the one above would be:: 

2353 

2354 a1 = aliased(Address) 

2355 a2 = aliased(Address) 

2356 

2357 q = ( 

2358 session.query(User) 

2359 .join(User.addresses.of_type(a1)) 

2360 .join(User.addresses.of_type(a2)) 

2361 .filter(a1.email_address == "ed@foo.com") 

2362 .filter(a2.email_address == "ed@bar.com") 

2363 ) 

2364 

2365 **Augmenting Built-in ON Clauses** 

2366 

2367 As a substitute for providing a full custom ON condition for an 

2368 existing relationship, the :meth:`_orm.PropComparator.and_` function 

2369 may be applied to a relationship attribute to augment additional 

2370 criteria into the ON clause; the additional criteria will be combined 

2371 with the default criteria using AND:: 

2372 

2373 q = session.query(User).join( 

2374 User.addresses.and_(Address.email_address != "foo@bar.com") 

2375 ) 

2376 

2377 .. versionadded:: 1.4 

2378 

2379 **Joining to Tables and Subqueries** 

2380 

2381 

2382 The target of a join may also be any table or SELECT statement, 

2383 which may be related to a target entity or not. Use the 

2384 appropriate ``.subquery()`` method in order to make a subquery 

2385 out of a query:: 

2386 

2387 subq = ( 

2388 session.query(Address) 

2389 .filter(Address.email_address == "ed@foo.com") 

2390 .subquery() 

2391 ) 

2392 

2393 

2394 q = session.query(User).join(subq, User.id == subq.c.user_id) 

2395 

2396 Joining to a subquery in terms of a specific relationship and/or 

2397 target entity may be achieved by linking the subquery to the 

2398 entity using :func:`_orm.aliased`:: 

2399 

2400 subq = ( 

2401 session.query(Address) 

2402 .filter(Address.email_address == "ed@foo.com") 

2403 .subquery() 

2404 ) 

2405 

2406 address_subq = aliased(Address, subq) 

2407 

2408 q = session.query(User).join(User.addresses.of_type(address_subq)) 

2409 

2410 **Controlling what to Join From** 

2411 

2412 In cases where the left side of the current state of 

2413 :class:`_query.Query` is not in line with what we want to join from, 

2414 the :meth:`_query.Query.select_from` method may be used:: 

2415 

2416 q = ( 

2417 session.query(Address) 

2418 .select_from(User) 

2419 .join(User.addresses) 

2420 .filter(User.name == "ed") 

2421 ) 

2422 

2423 Which will produce SQL similar to: 

2424 

2425 .. sourcecode:: sql 

2426 

2427 SELECT address.* FROM user 

2428 JOIN address ON user.id=address.user_id 

2429 WHERE user.name = :name_1 

2430 

2431 .. seealso:: 

2432 

2433 :meth:`_sql.Select.join` - v2 equivalent method. 

2434 

2435 :param \*props: Incoming arguments for :meth:`_query.Query.join`, 

2436 the props collection in modern use should be considered to be a one 

2437 or two argument form, either as a single "target" entity or ORM 

2438 attribute-bound relationship, or as a target entity plus an "on 

2439 clause" which may be a SQL expression or ORM attribute-bound 

2440 relationship. 

2441 

2442 :param isouter=False: If True, the join used will be a left outer join, 

2443 just as if the :meth:`_query.Query.outerjoin` method were called. 

2444 

2445 :param full=False: render FULL OUTER JOIN; implies ``isouter``. 

2446 

2447 """ 

2448 

2449 join_target = coercions.expect( 

2450 roles.JoinTargetRole, 

2451 target, 

2452 apply_propagate_attrs=self, 

2453 legacy=True, 

2454 ) 

2455 if onclause is not None: 

2456 onclause_element = coercions.expect( 

2457 roles.OnClauseRole, onclause, legacy=True 

2458 ) 

2459 else: 

2460 onclause_element = None 

2461 

2462 self._setup_joins += ( 

2463 ( 

2464 join_target, 

2465 onclause_element, 

2466 None, 

2467 { 

2468 "isouter": isouter, 

2469 "full": full, 

2470 }, 

2471 ), 

2472 ) 

2473 

2474 self.__dict__.pop("_last_joined_entity", None) 

2475 return self 

2476 

2477 def outerjoin( 

2478 self, 

2479 target: _JoinTargetArgument, 

2480 onclause: Optional[_OnClauseArgument] = None, 

2481 *, 

2482 full: bool = False, 

2483 ) -> Self: 

2484 """Create a left outer join against this ``Query`` object's criterion 

2485 and apply generatively, returning the newly resulting ``Query``. 

2486 

2487 Usage is the same as the ``join()`` method. 

2488 

2489 .. seealso:: 

2490 

2491 :meth:`_sql.Select.outerjoin` - v2 equivalent method. 

2492 

2493 """ 

2494 return self.join(target, onclause=onclause, isouter=True, full=full) 

2495 

2496 @_generative 

2497 @_assertions(_no_statement_condition) 

2498 def reset_joinpoint(self) -> Self: 

2499 """Return a new :class:`.Query`, where the "join point" has 

2500 been reset back to the base FROM entities of the query. 

2501 

2502 This method is usually used in conjunction with the 

2503 ``aliased=True`` feature of the :meth:`~.Query.join` 

2504 method. See the example in :meth:`~.Query.join` for how 

2505 this is used. 

2506 

2507 """ 

2508 self._last_joined_entity = None 

2509 

2510 return self 

2511 

2512 @_generative 

2513 @_assertions(_no_clauseelement_condition) 

2514 def select_from(self, *from_obj: _FromClauseArgument) -> Self: 

2515 r"""Set the FROM clause of this :class:`.Query` explicitly. 

2516 

2517 :meth:`.Query.select_from` is often used in conjunction with 

2518 :meth:`.Query.join` in order to control which entity is selected 

2519 from on the "left" side of the join. 

2520 

2521 The entity or selectable object here effectively replaces the 

2522 "left edge" of any calls to :meth:`~.Query.join`, when no 

2523 joinpoint is otherwise established - usually, the default "join 

2524 point" is the leftmost entity in the :class:`~.Query` object's 

2525 list of entities to be selected. 

2526 

2527 A typical example:: 

2528 

2529 q = ( 

2530 session.query(Address) 

2531 .select_from(User) 

2532 .join(User.addresses) 

2533 .filter(User.name == "ed") 

2534 ) 

2535 

2536 Which produces SQL equivalent to: 

2537 

2538 .. sourcecode:: sql 

2539 

2540 SELECT address.* FROM user 

2541 JOIN address ON user.id=address.user_id 

2542 WHERE user.name = :name_1 

2543 

2544 :param \*from_obj: collection of one or more entities to apply 

2545 to the FROM clause. Entities can be mapped classes, 

2546 :class:`.AliasedClass` objects, :class:`.Mapper` objects 

2547 as well as core :class:`.FromClause` elements like subqueries. 

2548 

2549 .. seealso:: 

2550 

2551 :meth:`~.Query.join` 

2552 

2553 :meth:`.Query.select_entity_from` 

2554 

2555 :meth:`_sql.Select.select_from` - v2 equivalent method. 

2556 

2557 """ 

2558 

2559 self._set_select_from(from_obj, False) 

2560 return self 

2561 

2562 @overload 

2563 def __getitem__(self, item: slice) -> List[_T]: ... 

2564 

2565 @overload 

2566 def __getitem__(self, item: SupportsIndex) -> _T: ... 

2567 

2568 def __getitem__(self, item: Any) -> Any: 

2569 return orm_util._getitem( 

2570 self, 

2571 item, 

2572 ) 

2573 

2574 @_generative 

2575 @_assertions(_no_statement_condition) 

2576 def slice( 

2577 self, 

2578 start: int, 

2579 stop: int, 

2580 ) -> Self: 

2581 """Computes the "slice" of the :class:`_query.Query` represented by 

2582 the given indices and returns the resulting :class:`_query.Query`. 

2583 

2584 The start and stop indices behave like the argument to Python's 

2585 built-in :func:`range` function. This method provides an 

2586 alternative to using ``LIMIT``/``OFFSET`` to get a slice of the 

2587 query. 

2588 

2589 For example, :: 

2590 

2591 session.query(User).order_by(User.id).slice(1, 3) 

2592 

2593 renders as 

2594 

2595 .. sourcecode:: sql 

2596 

2597 SELECT users.id AS users_id, 

2598 users.name AS users_name 

2599 FROM users ORDER BY users.id 

2600 LIMIT ? OFFSET ? 

2601 (2, 1) 

2602 

2603 .. seealso:: 

2604 

2605 :meth:`_query.Query.limit` 

2606 

2607 :meth:`_query.Query.offset` 

2608 

2609 :meth:`_sql.Select.slice` - v2 equivalent method. 

2610 

2611 """ 

2612 

2613 self._limit_clause, self._offset_clause = sql_util._make_slice( 

2614 self._limit_clause, self._offset_clause, start, stop 

2615 ) 

2616 return self 

2617 

2618 @_generative 

2619 @_assertions(_no_statement_condition) 

2620 def limit(self, limit: _LimitOffsetType) -> Self: 

2621 """Apply a ``LIMIT`` to the query and return the newly resulting 

2622 ``Query``. 

2623 

2624 .. seealso:: 

2625 

2626 :meth:`_sql.Select.limit` - v2 equivalent method. 

2627 

2628 """ 

2629 self._limit_clause = sql_util._offset_or_limit_clause(limit) 

2630 return self 

2631 

2632 @_generative 

2633 @_assertions(_no_statement_condition) 

2634 def offset(self, offset: _LimitOffsetType) -> Self: 

2635 """Apply an ``OFFSET`` to the query and return the newly resulting 

2636 ``Query``. 

2637 

2638 .. seealso:: 

2639 

2640 :meth:`_sql.Select.offset` - v2 equivalent method. 

2641 """ 

2642 self._offset_clause = sql_util._offset_or_limit_clause(offset) 

2643 return self 

2644 

2645 @_generative 

2646 @_assertions(_no_statement_condition) 

2647 def distinct(self, *expr: _ColumnExpressionArgument[Any]) -> Self: 

2648 r"""Apply a ``DISTINCT`` to the query and return the newly resulting 

2649 ``Query``. 

2650 

2651 

2652 .. note:: 

2653 

2654 The ORM-level :meth:`.distinct` call includes logic that will 

2655 automatically add columns from the ORDER BY of the query to the 

2656 columns clause of the SELECT statement, to satisfy the common need 

2657 of the database backend that ORDER BY columns be part of the SELECT 

2658 list when DISTINCT is used. These columns *are not* added to the 

2659 list of columns actually fetched by the :class:`_query.Query`, 

2660 however, 

2661 so would not affect results. The columns are passed through when 

2662 using the :attr:`_query.Query.statement` accessor, however. 

2663 

2664 .. deprecated:: 2.0 This logic is deprecated and will be removed 

2665 in SQLAlchemy 2.0. See :ref:`migration_20_query_distinct` 

2666 for a description of this use case in 2.0. 

2667 

2668 .. seealso:: 

2669 

2670 :meth:`_sql.Select.distinct` - v2 equivalent method. 

2671 

2672 :param \*expr: optional column expressions. When present, 

2673 the PostgreSQL dialect will render a ``DISTINCT ON (<expressions>)`` 

2674 construct. 

2675 

2676 .. deprecated:: 1.4 Using \*expr in other dialects is deprecated 

2677 and will raise :class:`_exc.CompileError` in a future version. 

2678 

2679 """ 

2680 if expr: 

2681 self._distinct = True 

2682 self._distinct_on = self._distinct_on + tuple( 

2683 coercions.expect(roles.ByOfRole, e) for e in expr 

2684 ) 

2685 else: 

2686 self._distinct = True 

2687 return self 

2688 

2689 def all(self) -> List[_T]: 

2690 """Return the results represented by this :class:`_query.Query` 

2691 as a list. 

2692 

2693 This results in an execution of the underlying SQL statement. 

2694 

2695 .. warning:: The :class:`_query.Query` object, 

2696 when asked to return either 

2697 a sequence or iterator that consists of full ORM-mapped entities, 

2698 will **deduplicate entries based on primary key**. See the FAQ for 

2699 more details. 

2700 

2701 .. seealso:: 

2702 

2703 :ref:`faq_query_deduplicating` 

2704 

2705 .. seealso:: 

2706 

2707 :meth:`_engine.Result.all` - v2 comparable method. 

2708 

2709 :meth:`_engine.Result.scalars` - v2 comparable method. 

2710 """ 

2711 return self._iter().all() # type: ignore 

2712 

2713 @_generative 

2714 @_assertions(_no_clauseelement_condition) 

2715 def from_statement(self, statement: ExecutableReturnsRows) -> Self: 

2716 """Execute the given SELECT statement and return results. 

2717 

2718 This method bypasses all internal statement compilation, and the 

2719 statement is executed without modification. 

2720 

2721 The statement is typically either a :func:`_expression.text` 

2722 or :func:`_expression.select` construct, and should return the set 

2723 of columns 

2724 appropriate to the entity class represented by this 

2725 :class:`_query.Query`. 

2726 

2727 .. seealso:: 

2728 

2729 :meth:`_sql.Select.from_statement` - v2 comparable method. 

2730 

2731 """ 

2732 statement = coercions.expect( 

2733 roles.SelectStatementRole, statement, apply_propagate_attrs=self 

2734 ) 

2735 self._statement = statement 

2736 return self 

2737 

2738 def first(self) -> Optional[_T]: 

2739 """Return the first result of this ``Query`` or 

2740 None if the result doesn't contain any row. 

2741 

2742 first() applies a limit of one within the generated SQL, so that 

2743 only one primary entity row is generated on the server side 

2744 (note this may consist of multiple result rows if join-loaded 

2745 collections are present). 

2746 

2747 Calling :meth:`_query.Query.first` 

2748 results in an execution of the underlying 

2749 query. 

2750 

2751 .. seealso:: 

2752 

2753 :meth:`_query.Query.one` 

2754 

2755 :meth:`_query.Query.one_or_none` 

2756 

2757 :meth:`_engine.Result.first` - v2 comparable method. 

2758 

2759 :meth:`_engine.Result.scalars` - v2 comparable method. 

2760 

2761 """ 

2762 # replicates limit(1) behavior 

2763 if self._statement is not None: 

2764 return self._iter().first() # type: ignore 

2765 else: 

2766 return self.limit(1)._iter().first() # type: ignore 

2767 

2768 def one_or_none(self) -> Optional[_T]: 

2769 """Return at most one result or raise an exception. 

2770 

2771 Returns ``None`` if the query selects 

2772 no rows. Raises ``sqlalchemy.orm.exc.MultipleResultsFound`` 

2773 if multiple object identities are returned, or if multiple 

2774 rows are returned for a query that returns only scalar values 

2775 as opposed to full identity-mapped entities. 

2776 

2777 Calling :meth:`_query.Query.one_or_none` 

2778 results in an execution of the 

2779 underlying query. 

2780 

2781 .. seealso:: 

2782 

2783 :meth:`_query.Query.first` 

2784 

2785 :meth:`_query.Query.one` 

2786 

2787 :meth:`_engine.Result.one_or_none` - v2 comparable method. 

2788 

2789 :meth:`_engine.Result.scalar_one_or_none` - v2 comparable method. 

2790 

2791 """ 

2792 return self._iter().one_or_none() # type: ignore 

2793 

2794 def one(self) -> _T: 

2795 """Return exactly one result or raise an exception. 

2796 

2797 Raises :class:`_exc.NoResultFound` if the query selects no rows. 

2798 Raises :class:`_exc.MultipleResultsFound` if multiple object identities 

2799 are returned, or if multiple rows are returned for a query that returns 

2800 only scalar values as opposed to full identity-mapped entities. 

2801 

2802 Calling :meth:`.one` results in an execution of the underlying query. 

2803 

2804 .. seealso:: 

2805 

2806 :meth:`_query.Query.first` 

2807 

2808 :meth:`_query.Query.one_or_none` 

2809 

2810 :meth:`_engine.Result.one` - v2 comparable method. 

2811 

2812 :meth:`_engine.Result.scalar_one` - v2 comparable method. 

2813 

2814 """ 

2815 return self._iter().one() # type: ignore 

2816 

2817 def scalar(self) -> Any: 

2818 """Return the first element of the first result or None 

2819 if no rows present. If multiple rows are returned, 

2820 raises :class:`_exc.MultipleResultsFound`. 

2821 

2822 >>> session.query(Item).scalar() 

2823 <Item> 

2824 >>> session.query(Item.id).scalar() 

2825 1 

2826 >>> session.query(Item.id).filter(Item.id < 0).scalar() 

2827 None 

2828 >>> session.query(Item.id, Item.name).scalar() 

2829 1 

2830 >>> session.query(func.count(Parent.id)).scalar() 

2831 20 

2832 

2833 This results in an execution of the underlying query. 

2834 

2835 .. seealso:: 

2836 

2837 :meth:`_engine.Result.scalar` - v2 comparable method. 

2838 

2839 """ 

2840 # TODO: not sure why we can't use result.scalar() here 

2841 try: 

2842 ret = self.one() 

2843 if not isinstance(ret, collections_abc.Sequence): 

2844 return ret 

2845 return ret[0] 

2846 except sa_exc.NoResultFound: 

2847 return None 

2848 

2849 def __iter__(self) -> Iterator[_T]: 

2850 result = self._iter() 

2851 try: 

2852 yield from result # type: ignore 

2853 except GeneratorExit: 

2854 # issue #8710 - direct iteration is not reusable after 

2855 # an iterable block is broken, so close the result 

2856 result._soft_close() 

2857 raise 

2858 

2859 def _iter(self) -> Union[ScalarResult[_T], Result[_T]]: 

2860 # new style execution. 

2861 params = self._params 

2862 

2863 statement = self._statement_20() 

2864 result: Union[ScalarResult[_T], Result[_T]] = self.session.execute( 

2865 statement, 

2866 params, 

2867 execution_options={"_sa_orm_load_options": self.load_options}, 

2868 ) 

2869 

2870 # legacy: automatically set scalars, unique 

2871 if result._attributes.get("is_single_entity", False): 

2872 result = cast("Result[_T]", result).scalars() 

2873 

2874 if ( 

2875 result._attributes.get("filtered", False) 

2876 and not self.load_options._yield_per 

2877 ): 

2878 result = result.unique() 

2879 

2880 return result 

2881 

2882 def __str__(self) -> str: 

2883 statement = self._statement_20() 

2884 

2885 try: 

2886 bind = ( 

2887 self._get_bind_args(statement, self.session.get_bind) 

2888 if self.session 

2889 else None 

2890 ) 

2891 except sa_exc.UnboundExecutionError: 

2892 bind = None 

2893 

2894 return str(statement.compile(bind)) 

2895 

2896 def _get_bind_args(self, statement: Any, fn: Any, **kw: Any) -> Any: 

2897 return fn(clause=statement, **kw) 

2898 

2899 @property 

2900 def column_descriptions(self) -> List[ORMColumnDescription]: 

2901 """Return metadata about the columns which would be 

2902 returned by this :class:`_query.Query`. 

2903 

2904 Format is a list of dictionaries:: 

2905 

2906 user_alias = aliased(User, name="user2") 

2907 q = sess.query(User, User.id, user_alias) 

2908 

2909 # this expression: 

2910 q.column_descriptions 

2911 

2912 # would return: 

2913 [ 

2914 { 

2915 "name": "User", 

2916 "type": User, 

2917 "aliased": False, 

2918 "expr": User, 

2919 "entity": User, 

2920 }, 

2921 { 

2922 "name": "id", 

2923 "type": Integer(), 

2924 "aliased": False, 

2925 "expr": User.id, 

2926 "entity": User, 

2927 }, 

2928 { 

2929 "name": "user2", 

2930 "type": User, 

2931 "aliased": True, 

2932 "expr": user_alias, 

2933 "entity": user_alias, 

2934 }, 

2935 ] 

2936 

2937 .. seealso:: 

2938 

2939 This API is available using :term:`2.0 style` queries as well, 

2940 documented at: 

2941 

2942 * :ref:`queryguide_inspection` 

2943 

2944 * :attr:`.Select.column_descriptions` 

2945 

2946 """ 

2947 

2948 return _column_descriptions(self, legacy=True) 

2949 

2950 @util.deprecated( 

2951 "2.0", 

2952 "The :meth:`_orm.Query.instances` method is deprecated and will " 

2953 "be removed in a future release. " 

2954 "Use the Select.from_statement() method or aliased() construct in " 

2955 "conjunction with Session.execute() instead.", 

2956 ) 

2957 def instances( 

2958 self, 

2959 result_proxy: CursorResult[Any], 

2960 context: Optional[QueryContext] = None, 

2961 ) -> Any: 

2962 """Return an ORM result given a :class:`_engine.CursorResult` and 

2963 :class:`.QueryContext`. 

2964 

2965 """ 

2966 if context is None: 

2967 util.warn_deprecated( 

2968 "Using the Query.instances() method without a context " 

2969 "is deprecated and will be disallowed in a future release. " 

2970 "Please make use of :meth:`_query.Query.from_statement` " 

2971 "for linking ORM results to arbitrary select constructs.", 

2972 version="1.4", 

2973 ) 

2974 compile_state = self._compile_state(for_statement=False) 

2975 

2976 context = QueryContext( 

2977 compile_state, 

2978 compile_state.statement, 

2979 compile_state.statement, 

2980 self._params, 

2981 self.session, 

2982 self.load_options, 

2983 ) 

2984 

2985 result = loading.instances(result_proxy, context) 

2986 

2987 # legacy: automatically set scalars, unique 

2988 if result._attributes.get("is_single_entity", False): 

2989 result = result.scalars() # type: ignore 

2990 

2991 if result._attributes.get("filtered", False): 

2992 result = result.unique() 

2993 

2994 # TODO: isn't this supposed to be a list? 

2995 return result 

2996 

2997 @util.became_legacy_20( 

2998 ":meth:`_orm.Query.merge_result`", 

2999 alternative="The method is superseded by the " 

3000 ":func:`_orm.merge_frozen_result` function.", 

3001 enable_warnings=False, # warnings occur via loading.merge_result 

3002 ) 

3003 def merge_result( 

3004 self, 

3005 iterator: Union[ 

3006 FrozenResult[Any], Iterable[Sequence[Any]], Iterable[object] 

3007 ], 

3008 load: bool = True, 

3009 ) -> Union[FrozenResult[Any], Iterable[Any]]: 

3010 """Merge a result into this :class:`_query.Query` object's Session. 

3011 

3012 Given an iterator returned by a :class:`_query.Query` 

3013 of the same structure 

3014 as this one, return an identical iterator of results, with all mapped 

3015 instances merged into the session using :meth:`.Session.merge`. This 

3016 is an optimized method which will merge all mapped instances, 

3017 preserving the structure of the result rows and unmapped columns with 

3018 less method overhead than that of calling :meth:`.Session.merge` 

3019 explicitly for each value. 

3020 

3021 The structure of the results is determined based on the column list of 

3022 this :class:`_query.Query` - if these do not correspond, 

3023 unchecked errors 

3024 will occur. 

3025 

3026 The 'load' argument is the same as that of :meth:`.Session.merge`. 

3027 

3028 For an example of how :meth:`_query.Query.merge_result` is used, see 

3029 the source code for the example :ref:`examples_caching`, where 

3030 :meth:`_query.Query.merge_result` is used to efficiently restore state 

3031 from a cache back into a target :class:`.Session`. 

3032 

3033 """ 

3034 

3035 return loading.merge_result(self, iterator, load) 

3036 

3037 def exists(self) -> Exists: 

3038 """A convenience method that turns a query into an EXISTS subquery 

3039 of the form EXISTS (SELECT 1 FROM ... WHERE ...). 

3040 

3041 e.g.:: 

3042 

3043 q = session.query(User).filter(User.name == "fred") 

3044 session.query(q.exists()) 

3045 

3046 Producing SQL similar to: 

3047 

3048 .. sourcecode:: sql 

3049 

3050 SELECT EXISTS ( 

3051 SELECT 1 FROM users WHERE users.name = :name_1 

3052 ) AS anon_1 

3053 

3054 The EXISTS construct is usually used in the WHERE clause:: 

3055 

3056 session.query(User.id).filter(q.exists()).scalar() 

3057 

3058 Note that some databases such as SQL Server don't allow an 

3059 EXISTS expression to be present in the columns clause of a 

3060 SELECT. To select a simple boolean value based on the exists 

3061 as a WHERE, use :func:`.literal`:: 

3062 

3063 from sqlalchemy import literal 

3064 

3065 session.query(literal(True)).filter(q.exists()).scalar() 

3066 

3067 .. seealso:: 

3068 

3069 :meth:`_sql.Select.exists` - v2 comparable method. 

3070 

3071 """ 

3072 

3073 # .add_columns() for the case that we are a query().select_from(X), 

3074 # so that ".statement" can be produced (#2995) but also without 

3075 # omitting the FROM clause from a query(X) (#2818); 

3076 # .with_only_columns() after we have a core select() so that 

3077 # we get just "SELECT 1" without any entities. 

3078 

3079 inner = ( 

3080 self.enable_eagerloads(False) 

3081 .add_columns(sql.literal_column("1")) 

3082 .set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL) 

3083 ._get_select_statement_only() 

3084 .with_only_columns(1) 

3085 ) 

3086 

3087 ezero = self._entity_from_pre_ent_zero() 

3088 if ezero is not None: 

3089 inner = inner.select_from(ezero) 

3090 

3091 return sql.exists(inner) 

3092 

3093 def count(self) -> int: 

3094 r"""Return a count of rows this the SQL formed by this :class:`Query` 

3095 would return. 

3096 

3097 This generates the SQL for this Query as follows: 

3098 

3099 .. sourcecode:: sql 

3100 

3101 SELECT count(1) AS count_1 FROM ( 

3102 SELECT <rest of query follows...> 

3103 ) AS anon_1 

3104 

3105 The above SQL returns a single row, which is the aggregate value 

3106 of the count function; the :meth:`_query.Query.count` 

3107 method then returns 

3108 that single integer value. 

3109 

3110 .. warning:: 

3111 

3112 It is important to note that the value returned by 

3113 count() is **not the same as the number of ORM objects that this 

3114 Query would return from a method such as the .all() method**. 

3115 The :class:`_query.Query` object, 

3116 when asked to return full entities, 

3117 will **deduplicate entries based on primary key**, meaning if the 

3118 same primary key value would appear in the results more than once, 

3119 only one object of that primary key would be present. This does 

3120 not apply to a query that is against individual columns. 

3121 

3122 .. seealso:: 

3123 

3124 :ref:`faq_query_deduplicating` 

3125 

3126 For fine grained control over specific columns to count, to skip the 

3127 usage of a subquery or otherwise control of the FROM clause, or to use 

3128 other aggregate functions, use :attr:`~sqlalchemy.sql.expression.func` 

3129 expressions in conjunction with :meth:`~.Session.query`, i.e.:: 

3130 

3131 from sqlalchemy import func 

3132 

3133 # count User records, without 

3134 # using a subquery. 

3135 session.query(func.count(User.id)) 

3136 

3137 # return count of user "id" grouped 

3138 # by "name" 

3139 session.query(func.count(User.id)).group_by(User.name) 

3140 

3141 from sqlalchemy import distinct 

3142 

3143 # count distinct "name" values 

3144 session.query(func.count(distinct(User.name))) 

3145 

3146 .. seealso:: 

3147 

3148 :ref:`migration_20_query_usage` 

3149 

3150 """ 

3151 col = sql.func.count(sql.literal_column("*")) 

3152 return ( # type: ignore 

3153 self._legacy_from_self(col).enable_eagerloads(False).scalar() 

3154 ) 

3155 

3156 def delete( 

3157 self, 

3158 synchronize_session: SynchronizeSessionArgument = "auto", 

3159 delete_args: Optional[Dict[Any, Any]] = None, 

3160 ) -> int: 

3161 r"""Perform a DELETE with an arbitrary WHERE clause. 

3162 

3163 Deletes rows matched by this query from the database. 

3164 

3165 E.g.:: 

3166 

3167 sess.query(User).filter(User.age == 25).delete(synchronize_session=False) 

3168 

3169 sess.query(User).filter(User.age == 25).delete( 

3170 synchronize_session="evaluate" 

3171 ) 

3172 

3173 .. warning:: 

3174 

3175 See the section :ref:`orm_expression_update_delete` for important 

3176 caveats and warnings, including limitations when using bulk UPDATE 

3177 and DELETE with mapper inheritance configurations. 

3178 

3179 :param synchronize_session: chooses the strategy to update the 

3180 attributes on objects in the session. See the section 

3181 :ref:`orm_expression_update_delete` for a discussion of these 

3182 strategies. 

3183 

3184 :param delete_args: Optional dictionary, if present will be passed 

3185 to the underlying :func:`_expression.delete` construct as the ``**kw`` 

3186 for the object. May be used to pass dialect-specific arguments such 

3187 as ``mysql_limit``. 

3188 

3189 .. versionadded:: 2.0.37 

3190 

3191 :return: the count of rows matched as returned by the database's 

3192 "row count" feature. 

3193 

3194 .. seealso:: 

3195 

3196 :ref:`orm_expression_update_delete` 

3197 

3198 """ # noqa: E501 

3199 

3200 bulk_del = BulkDelete(self, delete_args) 

3201 if self.dispatch.before_compile_delete: 

3202 for fn in self.dispatch.before_compile_delete: 

3203 new_query = fn(bulk_del.query, bulk_del) 

3204 if new_query is not None: 

3205 bulk_del.query = new_query 

3206 

3207 self = bulk_del.query 

3208 

3209 delete_ = sql.delete(*self._raw_columns) # type: ignore 

3210 

3211 if delete_args: 

3212 delete_ = delete_.with_dialect_options(**delete_args) 

3213 

3214 delete_._where_criteria = self._where_criteria 

3215 result = cast( 

3216 "CursorResult[Any]", 

3217 self.session.execute( 

3218 delete_, 

3219 self._params, 

3220 execution_options=self._execution_options.union( 

3221 {"synchronize_session": synchronize_session} 

3222 ), 

3223 ), 

3224 ) 

3225 bulk_del.result = result # type: ignore 

3226 self.session.dispatch.after_bulk_delete(bulk_del) 

3227 result.close() 

3228 

3229 return result.rowcount 

3230 

3231 def update( 

3232 self, 

3233 values: Dict[_DMLColumnArgument, Any], 

3234 synchronize_session: SynchronizeSessionArgument = "auto", 

3235 update_args: Optional[Dict[Any, Any]] = None, 

3236 ) -> int: 

3237 r"""Perform an UPDATE with an arbitrary WHERE clause. 

3238 

3239 Updates rows matched by this query in the database. 

3240 

3241 E.g.:: 

3242 

3243 sess.query(User).filter(User.age == 25).update( 

3244 {User.age: User.age - 10}, synchronize_session=False 

3245 ) 

3246 

3247 sess.query(User).filter(User.age == 25).update( 

3248 {"age": User.age - 10}, synchronize_session="evaluate" 

3249 ) 

3250 

3251 .. warning:: 

3252 

3253 See the section :ref:`orm_expression_update_delete` for important 

3254 caveats and warnings, including limitations when using arbitrary 

3255 UPDATE and DELETE with mapper inheritance configurations. 

3256 

3257 :param values: a dictionary with attributes names, or alternatively 

3258 mapped attributes or SQL expressions, as keys, and literal 

3259 values or sql expressions as values. If :ref:`parameter-ordered 

3260 mode <tutorial_parameter_ordered_updates>` is desired, the values can 

3261 be passed as a list of 2-tuples; this requires that the 

3262 :paramref:`~sqlalchemy.sql.expression.update.preserve_parameter_order` 

3263 flag is passed to the :paramref:`.Query.update.update_args` dictionary 

3264 as well. 

3265 

3266 :param synchronize_session: chooses the strategy to update the 

3267 attributes on objects in the session. See the section 

3268 :ref:`orm_expression_update_delete` for a discussion of these 

3269 strategies. 

3270 

3271 :param update_args: Optional dictionary, if present will be passed 

3272 to the underlying :func:`_expression.update` construct as the ``**kw`` 

3273 for the object. May be used to pass dialect-specific arguments such 

3274 as ``mysql_limit``, as well as other special arguments such as 

3275 :paramref:`~sqlalchemy.sql.expression.update.preserve_parameter_order`. 

3276 

3277 :return: the count of rows matched as returned by the database's 

3278 "row count" feature. 

3279 

3280 

3281 .. seealso:: 

3282 

3283 :ref:`orm_expression_update_delete` 

3284 

3285 """ 

3286 

3287 update_args = update_args or {} 

3288 

3289 bulk_ud = BulkUpdate(self, values, update_args) 

3290 

3291 if self.dispatch.before_compile_update: 

3292 for fn in self.dispatch.before_compile_update: 

3293 new_query = fn(bulk_ud.query, bulk_ud) 

3294 if new_query is not None: 

3295 bulk_ud.query = new_query 

3296 self = bulk_ud.query 

3297 

3298 upd = sql.update(*self._raw_columns) # type: ignore 

3299 

3300 ppo = update_args.pop("preserve_parameter_order", False) 

3301 if ppo: 

3302 upd = upd.ordered_values(*values) # type: ignore 

3303 else: 

3304 upd = upd.values(values) 

3305 if update_args: 

3306 upd = upd.with_dialect_options(**update_args) 

3307 

3308 upd._where_criteria = self._where_criteria 

3309 result = cast( 

3310 "CursorResult[Any]", 

3311 self.session.execute( 

3312 upd, 

3313 self._params, 

3314 execution_options=self._execution_options.union( 

3315 {"synchronize_session": synchronize_session} 

3316 ), 

3317 ), 

3318 ) 

3319 bulk_ud.result = result # type: ignore 

3320 self.session.dispatch.after_bulk_update(bulk_ud) 

3321 result.close() 

3322 return result.rowcount 

3323 

3324 def _compile_state( 

3325 self, for_statement: bool = False, **kw: Any 

3326 ) -> ORMCompileState: 

3327 """Create an out-of-compiler ORMCompileState object. 

3328 

3329 The ORMCompileState object is normally created directly as a result 

3330 of the SQLCompiler.process() method being handed a Select() 

3331 or FromStatement() object that uses the "orm" plugin. This method 

3332 provides a means of creating this ORMCompileState object directly 

3333 without using the compiler. 

3334 

3335 This method is used only for deprecated cases, which include 

3336 the .from_self() method for a Query that has multiple levels 

3337 of .from_self() in use, as well as the instances() method. It is 

3338 also used within the test suite to generate ORMCompileState objects 

3339 for test purposes. 

3340 

3341 """ 

3342 

3343 stmt = self._statement_20(for_statement=for_statement, **kw) 

3344 assert for_statement == stmt._compile_options._for_statement 

3345 

3346 # this chooses between ORMFromStatementCompileState and 

3347 # ORMSelectCompileState. We could also base this on 

3348 # query._statement is not None as we have the ORM Query here 

3349 # however this is the more general path. 

3350 compile_state_cls = cast( 

3351 ORMCompileState, 

3352 ORMCompileState._get_plugin_class_for_plugin(stmt, "orm"), 

3353 ) 

3354 

3355 return compile_state_cls._create_orm_context( 

3356 stmt, toplevel=True, compiler=None 

3357 ) 

3358 

3359 def _compile_context(self, for_statement: bool = False) -> QueryContext: 

3360 compile_state = self._compile_state(for_statement=for_statement) 

3361 context = QueryContext( 

3362 compile_state, 

3363 compile_state.statement, 

3364 compile_state.statement, 

3365 self._params, 

3366 self.session, 

3367 self.load_options, 

3368 ) 

3369 

3370 return context 

3371 

3372 

3373class AliasOption(interfaces.LoaderOption): 

3374 inherit_cache = False 

3375 

3376 @util.deprecated( 

3377 "1.4", 

3378 "The :class:`.AliasOption` object is not necessary " 

3379 "for entities to be matched up to a query that is established " 

3380 "via :meth:`.Query.from_statement` and now does nothing.", 

3381 ) 

3382 def __init__(self, alias: Union[Alias, Subquery]): 

3383 r"""Return a :class:`.MapperOption` that will indicate to the 

3384 :class:`_query.Query` 

3385 that the main table has been aliased. 

3386 

3387 """ 

3388 

3389 def process_compile_state(self, compile_state: ORMCompileState) -> None: 

3390 pass 

3391 

3392 

3393class BulkUD: 

3394 """State used for the orm.Query version of update() / delete(). 

3395 

3396 This object is now specific to Query only. 

3397 

3398 """ 

3399 

3400 def __init__(self, query: Query[Any]): 

3401 self.query = query.enable_eagerloads(False) 

3402 self._validate_query_state() 

3403 self.mapper = self.query._entity_from_pre_ent_zero() 

3404 

3405 def _validate_query_state(self) -> None: 

3406 for attr, methname, notset, op in ( 

3407 ("_limit_clause", "limit()", None, operator.is_), 

3408 ("_offset_clause", "offset()", None, operator.is_), 

3409 ("_order_by_clauses", "order_by()", (), operator.eq), 

3410 ("_group_by_clauses", "group_by()", (), operator.eq), 

3411 ("_distinct", "distinct()", False, operator.is_), 

3412 ( 

3413 "_from_obj", 

3414 "join(), outerjoin(), select_from(), or from_self()", 

3415 (), 

3416 operator.eq, 

3417 ), 

3418 ( 

3419 "_setup_joins", 

3420 "join(), outerjoin(), select_from(), or from_self()", 

3421 (), 

3422 operator.eq, 

3423 ), 

3424 ): 

3425 if not op(getattr(self.query, attr), notset): 

3426 raise sa_exc.InvalidRequestError( 

3427 "Can't call Query.update() or Query.delete() " 

3428 "when %s has been called" % (methname,) 

3429 ) 

3430 

3431 @property 

3432 def session(self) -> Session: 

3433 return self.query.session 

3434 

3435 

3436class BulkUpdate(BulkUD): 

3437 """BulkUD which handles UPDATEs.""" 

3438 

3439 def __init__( 

3440 self, 

3441 query: Query[Any], 

3442 values: Dict[_DMLColumnArgument, Any], 

3443 update_kwargs: Optional[Dict[Any, Any]], 

3444 ): 

3445 super().__init__(query) 

3446 self.values = values 

3447 self.update_kwargs = update_kwargs 

3448 

3449 

3450class BulkDelete(BulkUD): 

3451 """BulkUD which handles DELETEs.""" 

3452 

3453 def __init__( 

3454 self, 

3455 query: Query[Any], 

3456 delete_kwargs: Optional[Dict[Any, Any]], 

3457 ): 

3458 super().__init__(query) 

3459 self.delete_kwargs = delete_kwargs 

3460 

3461 

3462class RowReturningQuery(Query[Row[_TP]]): 

3463 if TYPE_CHECKING: 

3464 

3465 def tuples(self) -> Query[_TP]: # type: ignore 

3466 ...