util.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  1. # orm/util.py
  2. # Copyright (C) 2005-2017 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: http://www.opensource.org/licenses/mit-license.php
  7. from .. import sql, util, event, exc as sa_exc, inspection
  8. from ..sql import expression, util as sql_util, operators
  9. from .interfaces import PropComparator, MapperProperty
  10. from . import attributes
  11. import re
  12. from .base import instance_str, state_str, state_class_str, attribute_str, \
  13. state_attribute_str, object_mapper, object_state, _none_set, _never_set
  14. from .base import class_mapper, _class_to_mapper
  15. from .base import InspectionAttr
  16. from .path_registry import PathRegistry
  17. all_cascades = frozenset(("delete", "delete-orphan", "all", "merge",
  18. "expunge", "save-update", "refresh-expire",
  19. "none"))
  20. class CascadeOptions(frozenset):
  21. """Keeps track of the options sent to relationship().cascade"""
  22. _add_w_all_cascades = all_cascades.difference([
  23. 'all', 'none', 'delete-orphan'])
  24. _allowed_cascades = all_cascades
  25. __slots__ = (
  26. 'save_update', 'delete', 'refresh_expire', 'merge',
  27. 'expunge', 'delete_orphan')
  28. def __new__(cls, value_list):
  29. if isinstance(value_list, util.string_types) or value_list is None:
  30. return cls.from_string(value_list)
  31. values = set(value_list)
  32. if values.difference(cls._allowed_cascades):
  33. raise sa_exc.ArgumentError(
  34. "Invalid cascade option(s): %s" %
  35. ", ".join([repr(x) for x in
  36. sorted(values.difference(cls._allowed_cascades))]))
  37. if "all" in values:
  38. values.update(cls._add_w_all_cascades)
  39. if "none" in values:
  40. values.clear()
  41. values.discard('all')
  42. self = frozenset.__new__(CascadeOptions, values)
  43. self.save_update = 'save-update' in values
  44. self.delete = 'delete' in values
  45. self.refresh_expire = 'refresh-expire' in values
  46. self.merge = 'merge' in values
  47. self.expunge = 'expunge' in values
  48. self.delete_orphan = "delete-orphan" in values
  49. if self.delete_orphan and not self.delete:
  50. util.warn("The 'delete-orphan' cascade "
  51. "option requires 'delete'.")
  52. return self
  53. def __repr__(self):
  54. return "CascadeOptions(%r)" % (
  55. ",".join([x for x in sorted(self)])
  56. )
  57. @classmethod
  58. def from_string(cls, arg):
  59. values = [
  60. c for c
  61. in re.split(r'\s*,\s*', arg or "")
  62. if c
  63. ]
  64. return cls(values)
  65. def _validator_events(
  66. desc, key, validator, include_removes, include_backrefs):
  67. """Runs a validation method on an attribute value to be set or
  68. appended.
  69. """
  70. if not include_backrefs:
  71. def detect_is_backref(state, initiator):
  72. impl = state.manager[key].impl
  73. return initiator.impl is not impl
  74. if include_removes:
  75. def append(state, value, initiator):
  76. if include_backrefs or not detect_is_backref(state, initiator):
  77. return validator(state.obj(), key, value, False)
  78. else:
  79. return value
  80. def set_(state, value, oldvalue, initiator):
  81. if include_backrefs or not detect_is_backref(state, initiator):
  82. return validator(state.obj(), key, value, False)
  83. else:
  84. return value
  85. def remove(state, value, initiator):
  86. if include_backrefs or not detect_is_backref(state, initiator):
  87. validator(state.obj(), key, value, True)
  88. else:
  89. def append(state, value, initiator):
  90. if include_backrefs or not detect_is_backref(state, initiator):
  91. return validator(state.obj(), key, value)
  92. else:
  93. return value
  94. def set_(state, value, oldvalue, initiator):
  95. if include_backrefs or not detect_is_backref(state, initiator):
  96. return validator(state.obj(), key, value)
  97. else:
  98. return value
  99. event.listen(desc, 'append', append, raw=True, retval=True)
  100. event.listen(desc, 'set', set_, raw=True, retval=True)
  101. if include_removes:
  102. event.listen(desc, "remove", remove, raw=True, retval=True)
  103. def polymorphic_union(table_map, typecolname,
  104. aliasname='p_union', cast_nulls=True):
  105. """Create a ``UNION`` statement used by a polymorphic mapper.
  106. See :ref:`concrete_inheritance` for an example of how
  107. this is used.
  108. :param table_map: mapping of polymorphic identities to
  109. :class:`.Table` objects.
  110. :param typecolname: string name of a "discriminator" column, which will be
  111. derived from the query, producing the polymorphic identity for
  112. each row. If ``None``, no polymorphic discriminator is generated.
  113. :param aliasname: name of the :func:`~sqlalchemy.sql.expression.alias()`
  114. construct generated.
  115. :param cast_nulls: if True, non-existent columns, which are represented
  116. as labeled NULLs, will be passed into CAST. This is a legacy behavior
  117. that is problematic on some backends such as Oracle - in which case it
  118. can be set to False.
  119. """
  120. colnames = util.OrderedSet()
  121. colnamemaps = {}
  122. types = {}
  123. for key in table_map:
  124. table = table_map[key]
  125. # mysql doesn't like selecting from a select;
  126. # make it an alias of the select
  127. if isinstance(table, sql.Select):
  128. table = table.alias()
  129. table_map[key] = table
  130. m = {}
  131. for c in table.c:
  132. colnames.add(c.key)
  133. m[c.key] = c
  134. types[c.key] = c.type
  135. colnamemaps[table] = m
  136. def col(name, table):
  137. try:
  138. return colnamemaps[table][name]
  139. except KeyError:
  140. if cast_nulls:
  141. return sql.cast(sql.null(), types[name]).label(name)
  142. else:
  143. return sql.type_coerce(sql.null(), types[name]).label(name)
  144. result = []
  145. for type, table in table_map.items():
  146. if typecolname is not None:
  147. result.append(
  148. sql.select([col(name, table) for name in colnames] +
  149. [sql.literal_column(
  150. sql_util._quote_ddl_expr(type)).
  151. label(typecolname)],
  152. from_obj=[table]))
  153. else:
  154. result.append(sql.select([col(name, table) for name in colnames],
  155. from_obj=[table]))
  156. return sql.union_all(*result).alias(aliasname)
  157. def identity_key(*args, **kwargs):
  158. """Generate "identity key" tuples, as are used as keys in the
  159. :attr:`.Session.identity_map` dictionary.
  160. This function has several call styles:
  161. * ``identity_key(class, ident)``
  162. This form receives a mapped class and a primary key scalar or
  163. tuple as an argument.
  164. E.g.::
  165. >>> identity_key(MyClass, (1, 2))
  166. (<class '__main__.MyClass'>, (1, 2))
  167. :param class: mapped class (must be a positional argument)
  168. :param ident: primary key, may be a scalar or tuple argument.
  169. * ``identity_key(instance=instance)``
  170. This form will produce the identity key for a given instance. The
  171. instance need not be persistent, only that its primary key attributes
  172. are populated (else the key will contain ``None`` for those missing
  173. values).
  174. E.g.::
  175. >>> instance = MyClass(1, 2)
  176. >>> identity_key(instance=instance)
  177. (<class '__main__.MyClass'>, (1, 2))
  178. In this form, the given instance is ultimately run though
  179. :meth:`.Mapper.identity_key_from_instance`, which will have the
  180. effect of performing a database check for the corresponding row
  181. if the object is expired.
  182. :param instance: object instance (must be given as a keyword arg)
  183. * ``identity_key(class, row=row)``
  184. This form is similar to the class/tuple form, except is passed a
  185. database result row as a :class:`.RowProxy` object.
  186. E.g.::
  187. >>> row = engine.execute("select * from table where a=1 and b=2").\
  188. first()
  189. >>> identity_key(MyClass, row=row)
  190. (<class '__main__.MyClass'>, (1, 2))
  191. :param class: mapped class (must be a positional argument)
  192. :param row: :class:`.RowProxy` row returned by a :class:`.ResultProxy`
  193. (must be given as a keyword arg)
  194. """
  195. if args:
  196. if len(args) == 1:
  197. class_ = args[0]
  198. try:
  199. row = kwargs.pop("row")
  200. except KeyError:
  201. ident = kwargs.pop("ident")
  202. elif len(args) == 2:
  203. class_, ident = args
  204. elif len(args) == 3:
  205. class_, ident = args
  206. else:
  207. raise sa_exc.ArgumentError(
  208. "expected up to three positional arguments, "
  209. "got %s" % len(args))
  210. if kwargs:
  211. raise sa_exc.ArgumentError("unknown keyword arguments: %s"
  212. % ", ".join(kwargs))
  213. mapper = class_mapper(class_)
  214. if "ident" in locals():
  215. return mapper.identity_key_from_primary_key(util.to_list(ident))
  216. return mapper.identity_key_from_row(row)
  217. instance = kwargs.pop("instance")
  218. if kwargs:
  219. raise sa_exc.ArgumentError("unknown keyword arguments: %s"
  220. % ", ".join(kwargs.keys))
  221. mapper = object_mapper(instance)
  222. return mapper.identity_key_from_instance(instance)
  223. class ORMAdapter(sql_util.ColumnAdapter):
  224. """ColumnAdapter subclass which excludes adaptation of entities from
  225. non-matching mappers.
  226. """
  227. def __init__(self, entity, equivalents=None, adapt_required=False,
  228. chain_to=None, allow_label_resolve=True,
  229. anonymize_labels=False):
  230. info = inspection.inspect(entity)
  231. self.mapper = info.mapper
  232. selectable = info.selectable
  233. is_aliased_class = info.is_aliased_class
  234. if is_aliased_class:
  235. self.aliased_class = entity
  236. else:
  237. self.aliased_class = None
  238. sql_util.ColumnAdapter.__init__(
  239. self, selectable, equivalents, chain_to,
  240. adapt_required=adapt_required,
  241. allow_label_resolve=allow_label_resolve,
  242. anonymize_labels=anonymize_labels,
  243. include_fn=self._include_fn
  244. )
  245. def _include_fn(self, elem):
  246. entity = elem._annotations.get('parentmapper', None)
  247. return not entity or entity.isa(self.mapper)
  248. class AliasedClass(object):
  249. r"""Represents an "aliased" form of a mapped class for usage with Query.
  250. The ORM equivalent of a :func:`sqlalchemy.sql.expression.alias`
  251. construct, this object mimics the mapped class using a
  252. __getattr__ scheme and maintains a reference to a
  253. real :class:`~sqlalchemy.sql.expression.Alias` object.
  254. Usage is via the :func:`.orm.aliased` function, or alternatively
  255. via the :func:`.orm.with_polymorphic` function.
  256. Usage example::
  257. # find all pairs of users with the same name
  258. user_alias = aliased(User)
  259. session.query(User, user_alias).\
  260. join((user_alias, User.id > user_alias.id)).\
  261. filter(User.name==user_alias.name)
  262. The resulting object is an instance of :class:`.AliasedClass`.
  263. This object implements an attribute scheme which produces the
  264. same attribute and method interface as the original mapped
  265. class, allowing :class:`.AliasedClass` to be compatible
  266. with any attribute technique which works on the original class,
  267. including hybrid attributes (see :ref:`hybrids_toplevel`).
  268. The :class:`.AliasedClass` can be inspected for its underlying
  269. :class:`.Mapper`, aliased selectable, and other information
  270. using :func:`.inspect`::
  271. from sqlalchemy import inspect
  272. my_alias = aliased(MyClass)
  273. insp = inspect(my_alias)
  274. The resulting inspection object is an instance of :class:`.AliasedInsp`.
  275. See :func:`.aliased` and :func:`.with_polymorphic` for construction
  276. argument descriptions.
  277. """
  278. def __init__(self, cls, alias=None,
  279. name=None,
  280. flat=False,
  281. adapt_on_names=False,
  282. # TODO: None for default here?
  283. with_polymorphic_mappers=(),
  284. with_polymorphic_discriminator=None,
  285. base_alias=None,
  286. use_mapper_path=False):
  287. mapper = _class_to_mapper(cls)
  288. if alias is None:
  289. alias = mapper._with_polymorphic_selectable.alias(
  290. name=name, flat=flat)
  291. self._aliased_insp = AliasedInsp(
  292. self,
  293. mapper,
  294. alias,
  295. name,
  296. with_polymorphic_mappers
  297. if with_polymorphic_mappers
  298. else mapper.with_polymorphic_mappers,
  299. with_polymorphic_discriminator
  300. if with_polymorphic_discriminator is not None
  301. else mapper.polymorphic_on,
  302. base_alias,
  303. use_mapper_path,
  304. adapt_on_names
  305. )
  306. self.__name__ = 'AliasedClass_%s' % mapper.class_.__name__
  307. def __getattr__(self, key):
  308. try:
  309. _aliased_insp = self.__dict__['_aliased_insp']
  310. except KeyError:
  311. raise AttributeError()
  312. else:
  313. for base in _aliased_insp._target.__mro__:
  314. try:
  315. attr = object.__getattribute__(base, key)
  316. except AttributeError:
  317. continue
  318. else:
  319. break
  320. else:
  321. raise AttributeError(key)
  322. if isinstance(attr, PropComparator):
  323. ret = attr.adapt_to_entity(_aliased_insp)
  324. setattr(self, key, ret)
  325. return ret
  326. elif hasattr(attr, 'func_code'):
  327. is_method = getattr(_aliased_insp._target, key, None)
  328. if is_method and is_method.__self__ is not None:
  329. return util.types.MethodType(attr.__func__, self, self)
  330. else:
  331. return None
  332. elif hasattr(attr, '__get__'):
  333. ret = attr.__get__(None, self)
  334. if isinstance(ret, PropComparator):
  335. return ret.adapt_to_entity(_aliased_insp)
  336. else:
  337. return ret
  338. else:
  339. return attr
  340. def __repr__(self):
  341. return '<AliasedClass at 0x%x; %s>' % (
  342. id(self), self._aliased_insp._target.__name__)
  343. class AliasedInsp(InspectionAttr):
  344. """Provide an inspection interface for an
  345. :class:`.AliasedClass` object.
  346. The :class:`.AliasedInsp` object is returned
  347. given an :class:`.AliasedClass` using the
  348. :func:`.inspect` function::
  349. from sqlalchemy import inspect
  350. from sqlalchemy.orm import aliased
  351. my_alias = aliased(MyMappedClass)
  352. insp = inspect(my_alias)
  353. Attributes on :class:`.AliasedInsp`
  354. include:
  355. * ``entity`` - the :class:`.AliasedClass` represented.
  356. * ``mapper`` - the :class:`.Mapper` mapping the underlying class.
  357. * ``selectable`` - the :class:`.Alias` construct which ultimately
  358. represents an aliased :class:`.Table` or :class:`.Select`
  359. construct.
  360. * ``name`` - the name of the alias. Also is used as the attribute
  361. name when returned in a result tuple from :class:`.Query`.
  362. * ``with_polymorphic_mappers`` - collection of :class:`.Mapper` objects
  363. indicating all those mappers expressed in the select construct
  364. for the :class:`.AliasedClass`.
  365. * ``polymorphic_on`` - an alternate column or SQL expression which
  366. will be used as the "discriminator" for a polymorphic load.
  367. .. seealso::
  368. :ref:`inspection_toplevel`
  369. """
  370. def __init__(self, entity, mapper, selectable, name,
  371. with_polymorphic_mappers, polymorphic_on,
  372. _base_alias, _use_mapper_path, adapt_on_names):
  373. self.entity = entity
  374. self.mapper = mapper
  375. self.selectable = selectable
  376. self.name = name
  377. self.with_polymorphic_mappers = with_polymorphic_mappers
  378. self.polymorphic_on = polymorphic_on
  379. self._base_alias = _base_alias or self
  380. self._use_mapper_path = _use_mapper_path
  381. self._adapter = sql_util.ColumnAdapter(
  382. selectable, equivalents=mapper._equivalent_columns,
  383. adapt_on_names=adapt_on_names, anonymize_labels=True)
  384. self._adapt_on_names = adapt_on_names
  385. self._target = mapper.class_
  386. for poly in self.with_polymorphic_mappers:
  387. if poly is not mapper:
  388. setattr(self.entity, poly.class_.__name__,
  389. AliasedClass(poly.class_, selectable, base_alias=self,
  390. adapt_on_names=adapt_on_names,
  391. use_mapper_path=_use_mapper_path))
  392. is_aliased_class = True
  393. "always returns True"
  394. @property
  395. def class_(self):
  396. """Return the mapped class ultimately represented by this
  397. :class:`.AliasedInsp`."""
  398. return self.mapper.class_
  399. @util.memoized_property
  400. def _path_registry(self):
  401. if self._use_mapper_path:
  402. return self.mapper._path_registry
  403. else:
  404. return PathRegistry.per_mapper(self)
  405. def __getstate__(self):
  406. return {
  407. 'entity': self.entity,
  408. 'mapper': self.mapper,
  409. 'alias': self.selectable,
  410. 'name': self.name,
  411. 'adapt_on_names': self._adapt_on_names,
  412. 'with_polymorphic_mappers':
  413. self.with_polymorphic_mappers,
  414. 'with_polymorphic_discriminator':
  415. self.polymorphic_on,
  416. 'base_alias': self._base_alias,
  417. 'use_mapper_path': self._use_mapper_path
  418. }
  419. def __setstate__(self, state):
  420. self.__init__(
  421. state['entity'],
  422. state['mapper'],
  423. state['alias'],
  424. state['name'],
  425. state['with_polymorphic_mappers'],
  426. state['with_polymorphic_discriminator'],
  427. state['base_alias'],
  428. state['use_mapper_path'],
  429. state['adapt_on_names']
  430. )
  431. def _adapt_element(self, elem):
  432. return self._adapter.traverse(elem).\
  433. _annotate({
  434. 'parententity': self,
  435. 'parentmapper': self.mapper}
  436. )
  437. def _entity_for_mapper(self, mapper):
  438. self_poly = self.with_polymorphic_mappers
  439. if mapper in self_poly:
  440. if mapper is self.mapper:
  441. return self
  442. else:
  443. return getattr(
  444. self.entity, mapper.class_.__name__)._aliased_insp
  445. elif mapper.isa(self.mapper):
  446. return self
  447. else:
  448. assert False, "mapper %s doesn't correspond to %s" % (
  449. mapper, self)
  450. @util.memoized_property
  451. def _memoized_values(self):
  452. return {}
  453. def _memo(self, key, callable_, *args, **kw):
  454. if key in self._memoized_values:
  455. return self._memoized_values[key]
  456. else:
  457. self._memoized_values[key] = value = callable_(*args, **kw)
  458. return value
  459. def __repr__(self):
  460. if self.with_polymorphic_mappers:
  461. with_poly = "(%s)" % ", ".join(
  462. mp.class_.__name__ for mp in self.with_polymorphic_mappers)
  463. else:
  464. with_poly = ""
  465. return '<AliasedInsp at 0x%x; %s%s>' % (
  466. id(self), self.class_.__name__, with_poly)
  467. inspection._inspects(AliasedClass)(lambda target: target._aliased_insp)
  468. inspection._inspects(AliasedInsp)(lambda target: target)
  469. def aliased(element, alias=None, name=None, flat=False, adapt_on_names=False):
  470. """Produce an alias of the given element, usually an :class:`.AliasedClass`
  471. instance.
  472. E.g.::
  473. my_alias = aliased(MyClass)
  474. session.query(MyClass, my_alias).filter(MyClass.id > my_alias.id)
  475. The :func:`.aliased` function is used to create an ad-hoc mapping
  476. of a mapped class to a new selectable. By default, a selectable
  477. is generated from the normally mapped selectable (typically a
  478. :class:`.Table`) using the :meth:`.FromClause.alias` method.
  479. However, :func:`.aliased` can also be used to link the class to
  480. a new :func:`.select` statement. Also, the :func:`.with_polymorphic`
  481. function is a variant of :func:`.aliased` that is intended to specify
  482. a so-called "polymorphic selectable", that corresponds to the union
  483. of several joined-inheritance subclasses at once.
  484. For convenience, the :func:`.aliased` function also accepts plain
  485. :class:`.FromClause` constructs, such as a :class:`.Table` or
  486. :func:`.select` construct. In those cases, the :meth:`.FromClause.alias`
  487. method is called on the object and the new :class:`.Alias` object
  488. returned. The returned :class:`.Alias` is not ORM-mapped in this case.
  489. :param element: element to be aliased. Is normally a mapped class,
  490. but for convenience can also be a :class:`.FromClause` element.
  491. :param alias: Optional selectable unit to map the element to. This should
  492. normally be a :class:`.Alias` object corresponding to the :class:`.Table`
  493. to which the class is mapped, or to a :func:`.select` construct that
  494. is compatible with the mapping. By default, a simple anonymous
  495. alias of the mapped table is generated.
  496. :param name: optional string name to use for the alias, if not specified
  497. by the ``alias`` parameter. The name, among other things, forms the
  498. attribute name that will be accessible via tuples returned by a
  499. :class:`.Query` object.
  500. :param flat: Boolean, will be passed through to the
  501. :meth:`.FromClause.alias` call so that aliases of :class:`.Join` objects
  502. don't include an enclosing SELECT. This can lead to more efficient
  503. queries in many circumstances. A JOIN against a nested JOIN will be
  504. rewritten as a JOIN against an aliased SELECT subquery on backends that
  505. don't support this syntax.
  506. .. versionadded:: 0.9.0
  507. .. seealso:: :meth:`.Join.alias`
  508. :param adapt_on_names: if True, more liberal "matching" will be used when
  509. mapping the mapped columns of the ORM entity to those of the
  510. given selectable - a name-based match will be performed if the
  511. given selectable doesn't otherwise have a column that corresponds
  512. to one on the entity. The use case for this is when associating
  513. an entity with some derived selectable such as one that uses
  514. aggregate functions::
  515. class UnitPrice(Base):
  516. __tablename__ = 'unit_price'
  517. ...
  518. unit_id = Column(Integer)
  519. price = Column(Numeric)
  520. aggregated_unit_price = Session.query(
  521. func.sum(UnitPrice.price).label('price')
  522. ).group_by(UnitPrice.unit_id).subquery()
  523. aggregated_unit_price = aliased(UnitPrice,
  524. alias=aggregated_unit_price, adapt_on_names=True)
  525. Above, functions on ``aggregated_unit_price`` which refer to
  526. ``.price`` will return the
  527. ``func.sum(UnitPrice.price).label('price')`` column, as it is
  528. matched on the name "price". Ordinarily, the "price" function
  529. wouldn't have any "column correspondence" to the actual
  530. ``UnitPrice.price`` column as it is not a proxy of the original.
  531. .. versionadded:: 0.7.3
  532. """
  533. if isinstance(element, expression.FromClause):
  534. if adapt_on_names:
  535. raise sa_exc.ArgumentError(
  536. "adapt_on_names only applies to ORM elements"
  537. )
  538. return element.alias(name, flat=flat)
  539. else:
  540. return AliasedClass(element, alias=alias, flat=flat,
  541. name=name, adapt_on_names=adapt_on_names)
  542. def with_polymorphic(base, classes, selectable=False,
  543. flat=False,
  544. polymorphic_on=None, aliased=False,
  545. innerjoin=False, _use_mapper_path=False,
  546. _existing_alias=None):
  547. """Produce an :class:`.AliasedClass` construct which specifies
  548. columns for descendant mappers of the given base.
  549. Using this method will ensure that each descendant mapper's
  550. tables are included in the FROM clause, and will allow filter()
  551. criterion to be used against those tables. The resulting
  552. instances will also have those columns already loaded so that
  553. no "post fetch" of those columns will be required.
  554. .. seealso::
  555. :ref:`with_polymorphic` - full discussion of
  556. :func:`.orm.with_polymorphic`.
  557. :param base: Base class to be aliased.
  558. :param classes: a single class or mapper, or list of
  559. class/mappers, which inherit from the base class.
  560. Alternatively, it may also be the string ``'*'``, in which case
  561. all descending mapped classes will be added to the FROM clause.
  562. :param aliased: when True, the selectable will be wrapped in an
  563. alias, that is ``(SELECT * FROM <fromclauses>) AS anon_1``.
  564. This can be important when using the with_polymorphic()
  565. to create the target of a JOIN on a backend that does not
  566. support parenthesized joins, such as SQLite and older
  567. versions of MySQL.
  568. :param flat: Boolean, will be passed through to the
  569. :meth:`.FromClause.alias` call so that aliases of :class:`.Join`
  570. objects don't include an enclosing SELECT. This can lead to more
  571. efficient queries in many circumstances. A JOIN against a nested JOIN
  572. will be rewritten as a JOIN against an aliased SELECT subquery on
  573. backends that don't support this syntax.
  574. Setting ``flat`` to ``True`` implies the ``aliased`` flag is
  575. also ``True``.
  576. .. versionadded:: 0.9.0
  577. .. seealso:: :meth:`.Join.alias`
  578. :param selectable: a table or select() statement that will
  579. be used in place of the generated FROM clause. This argument is
  580. required if any of the desired classes use concrete table
  581. inheritance, since SQLAlchemy currently cannot generate UNIONs
  582. among tables automatically. If used, the ``selectable`` argument
  583. must represent the full set of tables and columns mapped by every
  584. mapped class. Otherwise, the unaccounted mapped columns will
  585. result in their table being appended directly to the FROM clause
  586. which will usually lead to incorrect results.
  587. :param polymorphic_on: a column to be used as the "discriminator"
  588. column for the given selectable. If not given, the polymorphic_on
  589. attribute of the base classes' mapper will be used, if any. This
  590. is useful for mappings that don't have polymorphic loading
  591. behavior by default.
  592. :param innerjoin: if True, an INNER JOIN will be used. This should
  593. only be specified if querying for one specific subtype only
  594. """
  595. primary_mapper = _class_to_mapper(base)
  596. if _existing_alias:
  597. assert _existing_alias.mapper is primary_mapper
  598. classes = util.to_set(classes)
  599. new_classes = set([
  600. mp.class_ for mp in
  601. _existing_alias.with_polymorphic_mappers])
  602. if classes == new_classes:
  603. return _existing_alias
  604. else:
  605. classes = classes.union(new_classes)
  606. mappers, selectable = primary_mapper.\
  607. _with_polymorphic_args(classes, selectable,
  608. innerjoin=innerjoin)
  609. if aliased or flat:
  610. selectable = selectable.alias(flat=flat)
  611. return AliasedClass(base,
  612. selectable,
  613. with_polymorphic_mappers=mappers,
  614. with_polymorphic_discriminator=polymorphic_on,
  615. use_mapper_path=_use_mapper_path)
  616. def _orm_annotate(element, exclude=None):
  617. """Deep copy the given ClauseElement, annotating each element with the
  618. "_orm_adapt" flag.
  619. Elements within the exclude collection will be cloned but not annotated.
  620. """
  621. return sql_util._deep_annotate(element, {'_orm_adapt': True}, exclude)
  622. def _orm_deannotate(element):
  623. """Remove annotations that link a column to a particular mapping.
  624. Note this doesn't affect "remote" and "foreign" annotations
  625. passed by the :func:`.orm.foreign` and :func:`.orm.remote`
  626. annotators.
  627. """
  628. return sql_util._deep_deannotate(element,
  629. values=("_orm_adapt", "parententity")
  630. )
  631. def _orm_full_deannotate(element):
  632. return sql_util._deep_deannotate(element)
  633. class _ORMJoin(expression.Join):
  634. """Extend Join to support ORM constructs as input."""
  635. __visit_name__ = expression.Join.__visit_name__
  636. def __init__(
  637. self,
  638. left, right, onclause=None, isouter=False,
  639. full=False, _left_memo=None, _right_memo=None):
  640. left_info = inspection.inspect(left)
  641. left_orm_info = getattr(left, '_joined_from_info', left_info)
  642. right_info = inspection.inspect(right)
  643. adapt_to = right_info.selectable
  644. self._joined_from_info = right_info
  645. self._left_memo = _left_memo
  646. self._right_memo = _right_memo
  647. if isinstance(onclause, util.string_types):
  648. onclause = getattr(left_orm_info.entity, onclause)
  649. if isinstance(onclause, attributes.QueryableAttribute):
  650. on_selectable = onclause.comparator._source_selectable()
  651. prop = onclause.property
  652. elif isinstance(onclause, MapperProperty):
  653. prop = onclause
  654. on_selectable = prop.parent.selectable
  655. else:
  656. prop = None
  657. if prop:
  658. if sql_util.clause_is_present(
  659. on_selectable, left_info.selectable):
  660. adapt_from = on_selectable
  661. else:
  662. adapt_from = left_info.selectable
  663. pj, sj, source, dest, \
  664. secondary, target_adapter = prop._create_joins(
  665. source_selectable=adapt_from,
  666. dest_selectable=adapt_to,
  667. source_polymorphic=True,
  668. dest_polymorphic=True,
  669. of_type=right_info.mapper)
  670. if sj is not None:
  671. if isouter:
  672. # note this is an inner join from secondary->right
  673. right = sql.join(secondary, right, sj)
  674. onclause = pj
  675. else:
  676. left = sql.join(left, secondary, pj, isouter)
  677. onclause = sj
  678. else:
  679. onclause = pj
  680. self._target_adapter = target_adapter
  681. expression.Join.__init__(self, left, right, onclause, isouter, full)
  682. if not prop and getattr(right_info, 'mapper', None) \
  683. and right_info.mapper.single:
  684. # if single inheritance target and we are using a manual
  685. # or implicit ON clause, augment it the same way we'd augment the
  686. # WHERE.
  687. single_crit = right_info.mapper._single_table_criterion
  688. if single_crit is not None:
  689. if right_info.is_aliased_class:
  690. single_crit = right_info._adapter.traverse(single_crit)
  691. self.onclause = self.onclause & single_crit
  692. def _splice_into_center(self, other):
  693. """Splice a join into the center.
  694. Given join(a, b) and join(b, c), return join(a, b).join(c)
  695. """
  696. leftmost = other
  697. while isinstance(leftmost, sql.Join):
  698. leftmost = leftmost.left
  699. assert self.right is leftmost
  700. left = _ORMJoin(
  701. self.left, other.left,
  702. self.onclause, isouter=self.isouter,
  703. _left_memo=self._left_memo,
  704. _right_memo=other._left_memo
  705. )
  706. return _ORMJoin(
  707. left,
  708. other.right,
  709. other.onclause, isouter=other.isouter,
  710. _right_memo=other._right_memo
  711. )
  712. def join(
  713. self, right, onclause=None,
  714. isouter=False, full=False, join_to_left=None):
  715. return _ORMJoin(self, right, onclause, full, isouter)
  716. def outerjoin(
  717. self, right, onclause=None,
  718. full=False, join_to_left=None):
  719. return _ORMJoin(self, right, onclause, True, full=full)
  720. def join(
  721. left, right, onclause=None, isouter=False,
  722. full=False, join_to_left=None):
  723. r"""Produce an inner join between left and right clauses.
  724. :func:`.orm.join` is an extension to the core join interface
  725. provided by :func:`.sql.expression.join()`, where the
  726. left and right selectables may be not only core selectable
  727. objects such as :class:`.Table`, but also mapped classes or
  728. :class:`.AliasedClass` instances. The "on" clause can
  729. be a SQL expression, or an attribute or string name
  730. referencing a configured :func:`.relationship`.
  731. :func:`.orm.join` is not commonly needed in modern usage,
  732. as its functionality is encapsulated within that of the
  733. :meth:`.Query.join` method, which features a
  734. significant amount of automation beyond :func:`.orm.join`
  735. by itself. Explicit usage of :func:`.orm.join`
  736. with :class:`.Query` involves usage of the
  737. :meth:`.Query.select_from` method, as in::
  738. from sqlalchemy.orm import join
  739. session.query(User).\
  740. select_from(join(User, Address, User.addresses)).\
  741. filter(Address.email_address=='foo@bar.com')
  742. In modern SQLAlchemy the above join can be written more
  743. succinctly as::
  744. session.query(User).\
  745. join(User.addresses).\
  746. filter(Address.email_address=='foo@bar.com')
  747. See :meth:`.Query.join` for information on modern usage
  748. of ORM level joins.
  749. .. versionchanged:: 0.8.1 - the ``join_to_left`` parameter
  750. is no longer used, and is deprecated.
  751. """
  752. return _ORMJoin(left, right, onclause, isouter, full)
  753. def outerjoin(left, right, onclause=None, full=False, join_to_left=None):
  754. """Produce a left outer join between left and right clauses.
  755. This is the "outer join" version of the :func:`.orm.join` function,
  756. featuring the same behavior except that an OUTER JOIN is generated.
  757. See that function's documentation for other usage details.
  758. """
  759. return _ORMJoin(left, right, onclause, True, full)
  760. def with_parent(instance, prop):
  761. """Create filtering criterion that relates this query's primary entity
  762. to the given related instance, using established :func:`.relationship()`
  763. configuration.
  764. The SQL rendered is the same as that rendered when a lazy loader
  765. would fire off from the given parent on that attribute, meaning
  766. that the appropriate state is taken from the parent object in
  767. Python without the need to render joins to the parent table
  768. in the rendered statement.
  769. .. versionchanged:: 0.6.4
  770. This method accepts parent instances in all
  771. persistence states, including transient, persistent, and detached.
  772. Only the requisite primary key/foreign key attributes need to
  773. be populated. Previous versions didn't work with transient
  774. instances.
  775. :param instance:
  776. An instance which has some :func:`.relationship`.
  777. :param property:
  778. String property name, or class-bound attribute, which indicates
  779. what relationship from the instance should be used to reconcile the
  780. parent/child relationship.
  781. """
  782. if isinstance(prop, util.string_types):
  783. mapper = object_mapper(instance)
  784. prop = getattr(mapper.class_, prop).property
  785. elif isinstance(prop, attributes.QueryableAttribute):
  786. prop = prop.property
  787. return prop._with_parent(instance)
  788. def has_identity(object):
  789. """Return True if the given object has a database
  790. identity.
  791. This typically corresponds to the object being
  792. in either the persistent or detached state.
  793. .. seealso::
  794. :func:`.was_deleted`
  795. """
  796. state = attributes.instance_state(object)
  797. return state.has_identity
  798. def was_deleted(object):
  799. """Return True if the given object was deleted
  800. within a session flush.
  801. This is regardless of whether or not the object is
  802. persistent or detached.
  803. .. versionadded:: 0.8.0
  804. .. seealso::
  805. :attr:`.InstanceState.was_deleted`
  806. """
  807. state = attributes.instance_state(object)
  808. return state.was_deleted
  809. def randomize_unitofwork():
  810. """Use random-ordering sets within the unit of work in order
  811. to detect unit of work sorting issues.
  812. This is a utility function that can be used to help reproduce
  813. inconsistent unit of work sorting issues. For example,
  814. if two kinds of objects A and B are being inserted, and
  815. B has a foreign key reference to A - the A must be inserted first.
  816. However, if there is no relationship between A and B, the unit of work
  817. won't know to perform this sorting, and an operation may or may not
  818. fail, depending on how the ordering works out. Since Python sets
  819. and dictionaries have non-deterministic ordering, such an issue may
  820. occur on some runs and not on others, and in practice it tends to
  821. have a great dependence on the state of the interpreter. This leads
  822. to so-called "heisenbugs" where changing entirely irrelevant aspects
  823. of the test program still cause the failure behavior to change.
  824. By calling ``randomize_unitofwork()`` when a script first runs, the
  825. ordering of a key series of sets within the unit of work implementation
  826. are randomized, so that the script can be minimized down to the
  827. fundamental mapping and operation that's failing, while still reproducing
  828. the issue on at least some runs.
  829. This utility is also available when running the test suite via the
  830. ``--reversetop`` flag.
  831. .. versionadded:: 0.8.1 created a standalone version of the
  832. ``--reversetop`` feature.
  833. """
  834. from sqlalchemy.orm import unitofwork, session, mapper, dependency
  835. from sqlalchemy.util import topological
  836. from sqlalchemy.testing.util import RandomSet
  837. topological.set = unitofwork.set = session.set = mapper.set = \
  838. dependency.set = RandomSet