1=============================
2What's new in SQLAlchemy 0.5?
3=============================
4
5.. admonition:: About this Document
6
7    This document describes changes between SQLAlchemy version 0.4,
8    last released October 12, 2008, and SQLAlchemy version 0.5,
9    last released January 16, 2010.
10
11    Document date: August 4, 2009
12
13
14This guide documents API changes which affect users
15migrating their applications from the 0.4 series of
16SQLAlchemy to 0.5.   It's also recommended for those working
17from  `Essential SQLAlchemy
18<https://oreilly.com/catalog/9780596516147/>`_, which only
19covers 0.4 and seems to even have some old 0.3isms in it.
20Note that SQLAlchemy 0.5 removes many behaviors which were
21deprecated throughout the span of the 0.4 series, and also
22deprecates more behaviors specific to 0.4.
23
24Major Documentation Changes
25===========================
26
27Some sections of the documentation have been completely
28rewritten and can serve as an introduction to new ORM
29features.  The ``Query`` and ``Session`` objects in
30particular have some distinct differences in API and
31behavior which fundamentally change many of the basic ways
32things are done, particularly with regards to constructing
33highly customized ORM queries and dealing with stale session
34state, commits and rollbacks.
35
36* `ORM Tutorial
37  <https://www.sqlalchemy.org/docs/05/ormtutorial.html>`_
38
39* `Session Documentation
40  <https://www.sqlalchemy.org/docs/05/session.html>`_
41
42Deprecations Source
43===================
44
45Another source of information is documented within a series
46of unit tests illustrating up to date usages of some common
47``Query`` patterns; this file can be viewed at
48[source:sqlalchemy/trunk/test/orm/test_deprecations.py].
49
50Requirements Changes
51====================
52
53* Python 2.4 or higher is required.  The SQLAlchemy 0.4 line
54  is the last version with Python 2.3 support.
55
56Object Relational Mapping
57=========================
58
59* **Column level expressions within Query.** - as detailed
60  in the `tutorial
61  <https://www.sqlalchemy.org/docs/05/ormtutorial.html>`_,
62  ``Query`` has the capability to create specific SELECT
63  statements, not just those against full rows:
64
65  ::
66
67      session.query(User.name, func.count(Address.id).label("numaddresses")).join(Address).group_by(User.name)
68
69  The tuples returned by any multi-column/entity query are
70  *named*' tuples:
71
72  ::
73
74      for row in session.query(User.name, func.count(Address.id).label('numaddresses')).join(Address).group_by(User.name):
75         print("name", row.name, "number", row.numaddresses)
76
77  ``Query`` has a ``statement`` accessor, as well as a
78  ``subquery()`` method which allow ``Query`` to be used to
79  create more complex combinations:
80
81  ::
82
83      subq = session.query(Keyword.id.label('keyword_id')).filter(Keyword.name.in_(['beans', 'carrots'])).subquery()
84      recipes = session.query(Recipe).filter(exists().
85         where(Recipe.id==recipe_keywords.c.recipe_id).
86         where(recipe_keywords.c.keyword_id==subq.c.keyword_id)
87      )
88
89* **Explicit ORM aliases are recommended for aliased joins**
90  - The ``aliased()`` function produces an "alias" of a
91  class, which allows fine-grained control of aliases in
92  conjunction with ORM queries.  While a table-level alias
93  (i.e. ``table.alias()``) is still usable, an ORM level
94  alias retains the semantics of the ORM mapped object which
95  is significant for inheritance mappings, options, and
96  other scenarios.  E.g.:
97
98  ::
99
100      Friend = aliased(Person)
101      session.query(Person, Friend).join((Friend, Person.friends)).all()
102
103* **query.join() greatly enhanced.** - You can now specify
104  the target and ON clause for a join in multiple ways.   A
105  target class alone can be provided where SQLA will attempt
106  to form a join to it via foreign key in the same way as
107  ``table.join(someothertable)``.  A target and an explicit
108  ON condition can be provided, where the ON condition can
109  be a ``relation()`` name, an actual class descriptor, or a
110  SQL expression.  Or the old way of just a ``relation()``
111  name or class descriptor works too.   See the ORM tutorial
112  which has several examples.
113
114* **Declarative is recommended for applications which don't
115  require (and don't prefer) abstraction between tables and
116  mappers** - The [/docs/05/reference/ext/declarative.html
117  Declarative] module, which is used to combine the
118  expression of ``Table``, ``mapper()``, and user defined
119  class objects together, is highly recommended as it
120  simplifies application configuration, ensures the "one
121  mapper per class" pattern, and allows the full range of
122  configuration available to distinct ``mapper()`` calls.
123  Separate ``mapper()`` and ``Table`` usage is now referred
124  to as "classical SQLAlchemy usage" and of course is freely
125  mixable with declarative.
126
127* **The .c. attribute has been removed** from classes (i.e.
128  ``MyClass.c.somecolumn``).  As is the case in 0.4, class-
129  level properties are usable as query elements, i.e.
130  ``Class.c.propname`` is now superseded by
131  ``Class.propname``, and the ``c`` attribute continues to
132  remain on ``Table`` objects where they indicate the
133  namespace of ``Column`` objects present on the table.
134
135  To get at the Table for a mapped class (if you didn't keep
136  it around already):
137
138  ::
139
140      table = class_mapper(someclass).mapped_table
141
142  Iterate through columns:
143
144  ::
145
146      for col in table.c:
147          print(col)
148
149  Work with a specific column:
150
151  ::
152
153      table.c.somecolumn
154
155  The class-bound descriptors support the full set of Column
156  operators as well as the documented relation-oriented
157  operators like ``has()``, ``any()``, ``contains()``, etc.
158
159  The reason for the hard removal of ``.c.`` is that in 0.5,
160  class-bound descriptors carry potentially different
161  meaning, as well as information regarding class mappings,
162  versus plain ``Column`` objects - and there are use cases
163  where you'd specifically want to use one or the other.
164  Generally, using class-bound descriptors invokes a set of
165  mapping/polymorphic aware translations, and using table-
166  bound columns does not.  In 0.4, these translations were
167  applied across the board to all expressions, but 0.5
168  differentiates completely between columns and mapped
169  descriptors, only applying translations to the latter.  So
170  in many cases, particularly when dealing with joined table
171  inheritance configurations as well as when using
172  ``query(<columns>)``, ``Class.propname`` and
173  ``table.c.colname`` are not interchangeable.
174
175  For example, ``session.query(users.c.id, users.c.name)``
176  is different versus ``session.query(User.id, User.name)``;
177  in the latter case, the ``Query`` is aware of the mapper
178  in use and further mapper-specific operations like
179  ``query.join(<propname>)``, ``query.with_parent()`` etc.
180  may be used, but in the former case cannot.  Additionally,
181  in polymorphic inheritance scenarios, the class-bound
182  descriptors refer to the columns present in the
183  polymorphic selectable in use, not necessarily the table
184  column which directly corresponds to the descriptor.  For
185  example, a set of classes related by joined-table
186  inheritance to the ``person`` table along the
187  ``person_id`` column of each table will all have their
188  ``Class.person_id`` attribute mapped to the ``person_id``
189  column in ``person``, and not their subclass table.
190  Version 0.4 would map this behavior onto table-bound
191  ``Column`` objects automatically.  In 0.5, this automatic
192  conversion has been removed, so that you in fact *can* use
193  table-bound columns as a means to override the
194  translations which occur with polymorphic querying; this
195  allows ``Query`` to be able to create optimized selects
196  among joined-table or concrete-table inheritance setups,
197  as well as portable subqueries, etc.
198
199* **Session Now Synchronizes Automatically with
200  Transactions.** Session now synchronizes against the
201  transaction automatically by default, including autoflush
202  and autoexpire.  A transaction is present at all times
203  unless disabled using the ``autocommit`` option.  When all
204  three flags are set to their default, the Session recovers
205  gracefully after rollbacks and it's very difficult to get
206  stale data into the session.  See the new Session
207  documentation for details.
208
209* **Implicit Order By Is Removed**.  This will impact ORM
210  users who rely upon SA's "implicit ordering" behavior,
211  which states that all Query objects which don't have an
212  ``order_by()`` will ORDER BY the "id" or "oid" column of
213  the primary mapped table, and all lazy/eagerly loaded
214  collections apply a similar ordering.   In 0.5, automatic
215  ordering must be explicitly configured on ``mapper()`` and
216  ``relation()`` objects (if desired), or otherwise when
217  using ``Query``.
218
219  To convert an 0.4 mapping to 0.5, such that its ordering
220  behavior will be extremely similar to 0.4 or previous, use
221  the ``order_by`` setting on ``mapper()`` and
222  ``relation()``:
223
224  ::
225
226          mapper(User, users, properties={
227              'addresses':relation(Address, order_by=addresses.c.id)
228          }, order_by=users.c.id)
229
230  To set ordering on a backref, use the ``backref()``
231  function:
232
233  ::
234
235          'keywords':relation(Keyword, secondary=item_keywords,
236                order_by=keywords.c.name, backref=backref('items', order_by=items.c.id))
237
238  Using declarative ?  To help with the new ``order_by``
239  requirement, ``order_by`` and friends can now be set using
240  strings which are evaluated in Python later on (this works
241  **only** with declarative, not plain mappers):
242
243  ::
244
245          class MyClass(MyDeclarativeBase):
246              ...
247              'addresses':relation("Address", order_by="Address.id")
248
249  It's generally a good idea to set ``order_by`` on
250  ``relation()s`` which load list-based collections of
251  items, since that ordering cannot otherwise be affected.
252  Other than that, the best practice is to use
253  ``Query.order_by()`` to control ordering of the primary
254  entities being loaded.
255
256* **Session is now
257  autoflush=True/autoexpire=True/autocommit=False.** - To
258  set it up, just call ``sessionmaker()`` with no arguments.
259  The name ``transactional=True`` is now
260  ``autocommit=False``.  Flushes occur upon each query
261  issued (disable with ``autoflush=False``), within each
262  ``commit()`` (as always), and before each
263  ``begin_nested()`` (so rolling back to the SAVEPOINT is
264  meaningful).   All objects are expired after each
265  ``commit()`` and after each ``rollback()``.  After
266  rollback, pending objects are expunged, deleted objects
267  move back to persistent.  These defaults work together
268  very nicely and there's really no more need for old
269  techniques like ``clear()`` (which is renamed to
270  ``expunge_all()`` as well).
271
272  P.S.:  sessions are now reusable after a ``rollback()``.
273  Scalar and collection attribute changes, adds and deletes
274  are all rolled back.
275
276* **session.add() replaces session.save(), session.update(),
277  session.save_or_update().** - the
278  ``session.add(someitem)`` and ``session.add_all([list of
279  items])`` methods replace ``save()``, ``update()``, and
280  ``save_or_update()``.  Those methods will remain
281  deprecated throughout 0.5.
282
283* **backref configuration made less verbose.** - The
284  ``backref()`` function now uses the ``primaryjoin`` and
285  ``secondaryjoin`` arguments of the forwards-facing
286  ``relation()`` when they are not explicitly stated.  It's
287  no longer necessary to specify
288  ``primaryjoin``/``secondaryjoin`` in both directions
289  separately.
290
291* **Simplified polymorphic options.** - The ORM's
292  "polymorphic load" behavior has been simplified.  In 0.4,
293  mapper() had an argument called ``polymorphic_fetch``
294  which could be configured as ``select`` or ``deferred``.
295  This option is removed; the mapper will now just defer any
296  columns which were not present in the SELECT statement.
297  The actual SELECT statement used is controlled by the
298  ``with_polymorphic`` mapper argument (which is also in 0.4
299  and replaces ``select_table``), as well as the
300  ``with_polymorphic()`` method on ``Query`` (also in 0.4).
301
302  An improvement to the deferred loading of inheriting
303  classes is that the mapper now produces the "optimized"
304  version of the SELECT statement in all cases; that is, if
305  class B inherits from A, and several attributes only
306  present on class B have been expired, the refresh
307  operation will only include B's table in the SELECT
308  statement and will not JOIN to A.
309
310* The ``execute()`` method on ``Session`` converts plain
311  strings into ``text()`` constructs, so that bind
312  parameters may all be specified as ":bindname" without
313  needing to call ``text()`` explicitly.  If "raw" SQL is
314  desired here, use ``session.connection().execute("raw
315  text")``.
316
317* ``session.Query().iterate_instances()`` has been renamed
318  to just ``instances()``. The old ``instances()`` method
319  returning a list instead of an iterator no longer exists.
320  If you were relying on that behavior, you should use
321  ``list(your_query.instances())``.
322
323Extending the ORM
324=================
325
326In 0.5 we're moving forward with more ways to modify and
327extend the ORM.  Heres a summary:
328
329* **MapperExtension.** - This is the classic extension
330  class, which remains.   Methods which should rarely be
331  needed are ``create_instance()`` and
332  ``populate_instance()``.  To control the initialization of
333  an object when it's loaded from the database, use the
334  ``reconstruct_instance()`` method, or more easily the
335  ``@reconstructor`` decorator described in the
336  documentation.
337
338* **SessionExtension.** - This is an easy to use extension
339  class for session events.  In particular, it provides
340  ``before_flush()``, ``after_flush()`` and
341  ``after_flush_postexec()`` methods.  This usage is
342  recommended over ``MapperExtension.before_XXX`` in many
343  cases since within ``before_flush()`` you can modify the
344  flush plan of the session freely, something which cannot
345  be done from within ``MapperExtension``.
346
347* **AttributeExtension.** - This class is now part of the
348  public API, and allows the interception of userland events
349  on attributes, including attribute set and delete
350  operations, and collection appends and removes.  It also
351  allows the value to be set or appended to be modified.
352  The ``@validates`` decorator, described in the
353  documentation, provides a quick way to mark any mapped
354  attributes as being "validated" by a particular class
355  method.
356
357* **Attribute Instrumentation Customization.** - An API is
358  provided for ambitious efforts to entirely replace
359  SQLAlchemy's attribute instrumentation, or just to augment
360  it in some cases.  This API was produced for the purposes
361  of the Trellis toolkit, but is available as a public API.
362  Some examples are provided in the distribution in the
363  ``/examples/custom_attributes`` directory.
364
365Schema/Types
366============
367
368* **String with no length no longer generates TEXT, it
369  generates VARCHAR** - The ``String`` type no longer
370  magically converts into a ``Text`` type when specified
371  with no length.  This only has an effect when CREATE TABLE
372  is issued, as it will issue ``VARCHAR`` with no length
373  parameter, which is not valid on many (but not all)
374  databases.  To create a TEXT (or CLOB, i.e. unbounded
375  string) column, use the ``Text`` type.
376
377* **PickleType() with mutable=True requires an __eq__()
378  method** - The ``PickleType`` type needs to compare values
379  when mutable=True.  The method of comparing
380  ``pickle.dumps()`` is inefficient and unreliable.  If an
381  incoming object does not implement ``__eq__()`` and is
382  also not ``None``, the ``dumps()`` comparison is used but
383  a warning is raised.  For types which implement
384  ``__eq__()`` which includes all dictionaries, lists, etc.,
385  comparison will use ``==`` and is now reliable by default.
386
387* **convert_bind_param() and convert_result_value() methods
388  of TypeEngine/TypeDecorator are removed.** - The O'Reilly
389  book unfortunately documented these methods even though
390  they were deprecated post 0.3.   For a user-defined type
391  which subclasses ``TypeEngine``, the ``bind_processor()``
392  and ``result_processor()`` methods should be used for
393  bind/result processing.  Any user defined type, whether
394  extending ``TypeEngine`` or ``TypeDecorator``, which uses
395  the old 0.3 style can be easily adapted to the new style
396  using the following adapter:
397
398  ::
399
400      class AdaptOldConvertMethods(object):
401          """A mixin which adapts 0.3-style convert_bind_param and
402          convert_result_value methods
403
404          """
405          def bind_processor(self, dialect):
406              def convert(value):
407                  return self.convert_bind_param(value, dialect)
408              return convert
409
410          def result_processor(self, dialect):
411              def convert(value):
412                  return self.convert_result_value(value, dialect)
413              return convert
414
415          def convert_result_value(self, value, dialect):
416              return value
417
418          def convert_bind_param(self, value, dialect):
419              return value
420
421  To use the above mixin:
422
423  ::
424
425      class MyType(AdaptOldConvertMethods, TypeEngine):
426         # ...
427
428* The ``quote`` flag on ``Column`` and ``Table`` as well as
429  the ``quote_schema`` flag on ``Table`` now control quoting
430  both positively and negatively.  The default is ``None``,
431  meaning let regular quoting rules take effect. When
432  ``True``, quoting is forced on.  When ``False``, quoting
433  is forced off.
434
435* Column ``DEFAULT`` value DDL can now be more conveniently
436  specified with ``Column(..., server_default='val')``,
437  deprecating ``Column(..., PassiveDefault('val'))``.
438  ``default=`` is now exclusively for Python-initiated
439  default values, and can coexist with server_default.  A
440  new ``server_default=FetchedValue()`` replaces the
441  ``PassiveDefault('')`` idiom for marking columns as
442  subject to influence from external triggers and has no DDL
443  side effects.
444
445* SQLite's ``DateTime``, ``Time`` and ``Date`` types now
446  **only accept datetime objects, not strings** as bind
447  parameter input.  If you'd like to create your own
448  "hybrid" type which accepts strings and returns results as
449  date objects (from whatever format you'd like), create a
450  ``TypeDecorator`` that builds on ``String``.  If you only
451  want string-based dates, just use ``String``.
452
453* Additionally, the ``DateTime`` and ``Time`` types, when
454  used with SQLite, now represent the "microseconds" field
455  of the Python ``datetime.datetime`` object in the same
456  manner as ``str(datetime)`` - as fractional seconds, not a
457  count of microseconds.  That is:
458
459  ::
460
461       dt = datetime.datetime(2008, 6, 27, 12, 0, 0, 125)  # 125 usec
462
463       # old way
464       '2008-06-27 12:00:00.125'
465
466       # new way
467       '2008-06-27 12:00:00.000125'
468
469  So if an existing SQLite file-based database intends to be
470  used across 0.4 and 0.5, you either have to upgrade the
471  datetime columns to store the new format (NOTE: please
472  test this, I'm pretty sure its correct):
473
474  ::
475
476       UPDATE mytable SET somedatecol =
477         substr(somedatecol, 0, 19) || '.' || substr((substr(somedatecol, 21, -1) / 1000000), 3, -1);
478
479  or, enable "legacy" mode as follows:
480
481  ::
482
483       from sqlalchemy.databases.sqlite import DateTimeMixin
484       DateTimeMixin.__legacy_microseconds__ = True
485
486Connection Pool no longer threadlocal by default
487================================================
488
4890.4 has an unfortunate default setting of
490"pool_threadlocal=True", leading to surprise behavior when,
491for example, using multiple Sessions within a single thread.
492This flag is now off in 0.5.   To re-enable 0.4's behavior,
493specify ``pool_threadlocal=True`` to ``create_engine()``, or
494alternatively use the "threadlocal" strategy via
495``strategy="threadlocal"``.
496
497\*args Accepted, \*args No Longer Accepted
498==========================================
499
500The policy with ``method(\*args)`` vs. ``method([args])``
501is, if the method accepts a variable-length set of items
502which represent a fixed structure, it takes ``\*args``.  If
503the method accepts a variable-length set of items that are
504data-driven, it takes ``[args]``.
505
506* The various Query.options() functions ``eagerload()``,
507  ``eagerload_all()``, ``lazyload()``, ``contains_eager()``,
508  ``defer()``, ``undefer()`` all accept variable-length
509  ``\*keys`` as their argument now, which allows a path to
510  be formulated using descriptors, ie.:
511
512  ::
513
514         query.options(eagerload_all(User.orders, Order.items, Item.keywords))
515
516  A single array argument is still accepted for backwards
517  compatibility.
518
519* Similarly, the ``Query.join()`` and ``Query.outerjoin()``
520  methods accept a variable length \*args, with a single
521  array accepted for backwards compatibility:
522
523  ::
524
525         query.join('orders', 'items')
526         query.join(User.orders, Order.items)
527
528* the ``in_()`` method on columns and similar only accepts a
529  list argument now.  It no longer accepts ``\*args``.
530
531Removed
532=======
533
534* **entity_name** - This feature was always problematic and
535  rarely used.  0.5's more deeply fleshed out use cases
536  revealed further issues with ``entity_name`` which led to
537  its removal.  If different mappings are required for a
538  single class, break the class into separate subclasses and
539  map them separately.  An example of this is at
540  [wiki:UsageRecipes/EntityName].  More information
541  regarding rationale is described at https://groups.google.c
542  om/group/sqlalchemy/browse_thread/thread/9e23a0641a88b96d?
543  hl=en .
544
545* **get()/load() cleanup**
546
547
548  The ``load()`` method has been removed.  Its
549  functionality was kind of arbitrary and basically copied
550  from Hibernate, where it's also not a particularly
551  meaningful method.
552
553  To get equivalent functionality:
554
555  ::
556
557       x = session.query(SomeClass).populate_existing().get(7)
558
559  ``Session.get(cls, id)`` and ``Session.load(cls, id)``
560  have been removed.  ``Session.get()`` is redundant vs.
561  ``session.query(cls).get(id)``.
562
563  ``MapperExtension.get()`` is also removed (as is
564  ``MapperExtension.load()``).  To override the
565  functionality of ``Query.get()``, use a subclass:
566
567  ::
568
569       class MyQuery(Query):
570           def get(self, ident):
571               # ...
572
573       session = sessionmaker(query_cls=MyQuery)()
574
575       ad1 = session.query(Address).get(1)
576
577* ``sqlalchemy.orm.relation()``
578
579
580  The following deprecated keyword arguments have been
581  removed:
582
583  foreignkey, association, private, attributeext, is_backref
584
585  In particular, ``attributeext`` is replaced with
586  ``extension`` - the ``AttributeExtension`` class is now in
587  the public API.
588
589* ``session.Query()``
590
591
592  The following deprecated functions have been removed:
593
594  list, scalar, count_by, select_whereclause, get_by,
595  select_by, join_by, selectfirst, selectone, select,
596  execute, select_statement, select_text, join_to, join_via,
597  selectfirst_by, selectone_by, apply_max, apply_min,
598  apply_avg, apply_sum
599
600  Additionally, the ``id`` keyword argument to ``join()``,
601  ``outerjoin()``, ``add_entity()`` and ``add_column()`` has
602  been removed.  To target table aliases in ``Query`` to
603  result columns, use the ``aliased`` construct:
604
605  ::
606
607      from sqlalchemy.orm import aliased
608      address_alias = aliased(Address)
609      print(session.query(User, address_alias).join((address_alias, User.addresses)).all())
610
611* ``sqlalchemy.orm.Mapper``
612
613
614  * instances()
615
616
617  * get_session() - this method was not very noticeable, but
618    had the effect of associating lazy loads with a
619    particular session even if the parent object was
620    entirely detached, when an extension such as
621    ``scoped_session()`` or the old ``SessionContextExt``
622    was used.  It's possible that some applications which
623    relied upon this behavior will no longer work as
624    expected;  but the better programming practice here is
625    to always ensure objects are present within sessions if
626    database access from their attributes are required.
627
628* ``mapper(MyClass, mytable)``
629
630
631  Mapped classes no are longer instrumented with a "c" class
632  attribute; e.g. ``MyClass.c``
633
634* ``sqlalchemy.orm.collections``
635
636
637  The _prepare_instrumentation alias for
638  prepare_instrumentation has been removed.
639
640* ``sqlalchemy.orm``
641
642
643  Removed the ``EXT_PASS`` alias of ``EXT_CONTINUE``.
644
645* ``sqlalchemy.engine``
646
647
648  The alias from ``DefaultDialect.preexecute_sequences`` to
649  ``.preexecute_pk_sequences`` has been removed.
650
651  The deprecated engine_descriptors() function has been
652  removed.
653
654* ``sqlalchemy.ext.activemapper``
655
656
657  Module removed.
658
659* ``sqlalchemy.ext.assignmapper``
660
661
662  Module removed.
663
664* ``sqlalchemy.ext.associationproxy``
665
666
667  Pass-through of keyword args on the proxy's
668  ``.append(item, \**kw)`` has been removed and is now
669  simply ``.append(item)``
670
671* ``sqlalchemy.ext.selectresults``,
672  ``sqlalchemy.mods.selectresults``
673
674  Modules removed.
675
676* ``sqlalchemy.ext.declarative``
677
678
679  ``declared_synonym()`` removed.
680
681* ``sqlalchemy.ext.sessioncontext``
682
683
684  Module removed.
685
686* ``sqlalchemy.log``
687
688
689  The ``SADeprecationWarning`` alias to
690  ``sqlalchemy.exc.SADeprecationWarning`` has been removed.
691
692* ``sqlalchemy.exc``
693
694
695  ``exc.AssertionError`` has been removed and usage replaced
696  by the Python built-in of the same name.
697
698* ``sqlalchemy.databases.mysql``
699
700
701  The deprecated ``get_version_info`` dialect method has
702  been removed.
703
704Renamed or Moved
705================
706
707* ``sqlalchemy.exceptions`` is now ``sqlalchemy.exc``
708
709
710  The module may still be imported under the old name until
711  0.6.
712
713* ``FlushError``, ``ConcurrentModificationError``,
714  ``UnmappedColumnError`` -> sqlalchemy.orm.exc
715
716  These exceptions moved to the orm package.  Importing
717  'sqlalchemy.orm' will install aliases in sqlalchemy.exc
718  for compatibility until 0.6.
719
720* ``sqlalchemy.logging`` -> ``sqlalchemy.log``
721
722
723  This internal module was renamed.  No longer needs to be
724  special cased when packaging SA with py2app and similar
725  tools that scan imports.
726
727* ``session.Query().iterate_instances()`` ->
728  ``session.Query().instances()``.
729
730Deprecated
731==========
732
733* ``Session.save()``, ``Session.update()``,
734  ``Session.save_or_update()``
735
736  All three replaced by ``Session.add()``
737
738* ``sqlalchemy.PassiveDefault``
739
740
741  Use ``Column(server_default=...)`` Translates to
742  sqlalchemy.DefaultClause() under the hood.
743
744* ``session.Query().iterate_instances()``. It has been
745  renamed to ``instances()``.
746
747