These will typically be used in conjunction with the :meth:`.Engine.connect`
method::
+ # 1.4 / 2.0 code
+
+ from sqlalchemy.future import create_engine
+
+ engine = create_engine(...)
+
with engine.connect() as conn:
conn.execute(some_table.insert().values(foo='bar'))
conn.commit()
:class:`.Session` will require that :meth:`.Session.begin` is called in order
to work with the database::
+ # 1.4 / 2.0 code
+
session = sessionmaker(autobegin=False)
with session.begin():
The above code is already available in current SQLAlchemy releases. Driver
-support is available for PostgreSQL, MySQL, SQL Server, and newer releases
-will include support for Oracle and SQLite as well.
+support is available for PostgreSQL, MySQL, SQL Server, and as of SQLAlchemy
+1.3.16 Oracle and SQLite as well.
.. _migration_20_implicit_execution:
to "one"::
- # one choice!
+ # one choice! (this works now!)
with engine.begin() as conn:
result = conn.execute(stmt)
- # OK one and a half choices:
+ # OK one and a half choices (the commit() is 1.4 / 2.0 using future engine):
with engine.connect() as conn:
result = conn.execute(stmt)
can be directly bound to a :class:`.Connection` or :class:`.Session` once
constructed::
+ # 1.4 / 2.0 code (tentative)
+
stmt = select(some_table).where(criteria)
with engine.begin() as conn:
to a series of statement executions in the same way as that of
:class:`.Connection`::
+ # 1.4 / 2.0 code
+
session = Session()
result = session.execution_options(stream_per=100).execute(stmt)
The interim signature will be::
+ # 1.4 / 2.0 using sqlalchemy.future.create_engine,
+ # sqlalchemy.orm.future.Session / sessionmaker / etc
+
def execute(self, statement, _params=None, **options):
That is, by naming "``_params``" with an underscore we suggest that this
The ``**options`` keywords will be another way of passing execution options.
So that an execution may look like::
+ # 1.4 / 2.0 future
+
result = connection.execute(table.insert(), {"foo": "bar"}, isolation_level='AUTOCOMMIT')
result = session.execute(stmt, stream_per=100)
the existing "ResultProxy" object, but will be present both in Core and ORM
equally::
+ # 1.4 / 2.0 with future create_engine
+
+ from sqlalchemy.future import create_engine
+
+ engine = create_engine(...)
+
with engine.begin() as conn:
stmt = table.insert()
In order to receive results as mappings up front, the ``mappings()`` modifier
on the result can be used::
+ from sqlalchemy.orm.future import Session
+
+ session = Session(some_engine)
+
result = session.execute(stmt)
for row in result.mappings():
print("the user is: %s" % row["User"])
The :class:`.Row` class as used by the ORM also supports access via entity
or attribute::
+ from sqlalchemy.future import select
+
stmt = select(User, Address).join(User.addresses)
for row in session.execute(stmt).mappings():
used. An alternative API that behaves just like ``mapper()`` can be defined
right now as follows::
+ # 1.xx code
+
from sqlalchemy.ext.declarative import base
def declarative_mapper():
_decl_class_registry = {}
can just as easily add the above ``mapper()`` function to any declarative base,
to make for a pattern such as::
- from sqlalchemy.orm import declarative_base
+ from sqlalchemy.orm.future import declarative_base
base = declarative_base()
then when delivered to the ``.invoke()`` or ``.execute()`` method of
:class:`.Session`, it will be interpreted appropriately::
+ from sqlalchemy.future import select
stmt = select(User).join(User.addresses).where(Address.email == 'foo@bar.com')
+ from sqlalchemy.orm.future import Session
+ session = Session(some_engine)
+
rows = session.execute(stmt).all()
Similarly, methods like :meth:`.Query.update` and :meth:`.Query.delete` are now
replaced by usage of the :func:`.update` and :func:`.delete` constructs directly::
+ from sqlalchemy.future import update
+
stmt = update(User).where(User.name == 'foo').values(name='bar')
session.invoke(stmt).execution_options(synchronize_session=False).execute()
# use instead
q = select(User).join(User.orders).join(Order.items).join(Item.keywords)
+.. _migration_20_query_join_options:
join(..., aliased=True), from_joinpoint removed
-----------------------------------------------
distinct is used. The following query will select from all User columns
as well as "address.email_address" but only return User objects::
+ # 1.xx code
+
result = session.query(User).join(User.addresses).\
distinct().order_by(Address.email_address).all()
objects back. In 2.0, this very unusual use case is performed explicitly,
and the limiting of the entities/columns to ``User`` is done on the result::
+ # 1.4/2.0 code
from sqlalchemy.future import select
entities, then converts itself to select just one of the entities from
a subquery::
+ # 1.xx code
+
q = session.query(User, Address.email_address).\
join(User.addresses).\
from_self(User).order_by(Address.email_address)
In 2.0, we perform these steps explicitly using :func:`.orm.aliased`::
+ # 1.4/2.0 code
+
+ from sqlalchemy.future import select
from sqlalchemy.orm import aliased
- subq = session.query(User, Address.email_address).\
+ subq = select(User, Address.email_address).\
join(User.addresses).subquery()
# state the User and Address entities both in terms of the subquery
aa = aliased(Address, subq)
# then select using those entities
- q = session.query(ua).order_by(aa.email_address)
+ stmt = select(ua).order_by(aa.email_address)
+ result = session.execute(stmt)
The above query renders the identical SQL structure, but uses a more
succinct labeling scheme that doesn't pull in table names (that labeling
we can select from both entities at once without having to specify any
particular labeling::
- subq = session.query(User, Address).\
+ # 1.4/2.0 code
+
+ subq = select(User, Address).\
join(User.addresses).subquery()
ua = aliased(User, subq)
aa = aliased(Address, subq)
- q = session.query(ua, aa).order_by(aa.email_address)
+ stmt = select(ua, aa).order_by(aa.email_address)
+ result = session.execute(stmt)
The above query will disambiguate the ``.id`` column of ``User`` and
``Address``, where ``Address.id`` is rendered and tracked as ``id_1``::
ORM rows returned by ``session.execute(stmt)`` are no longer automatically
"uniqued"; this must be called explicitly::
+ # 1.4 / 2.0 code
+
stmt = select(User).options(joinedload(User.addresses))
# statement will raise if unique() is not used, due to joinedload()
Again this is an often requested behavior
at the ORM level so something will have to happen in this regard
-The :meth:`.InvocationContext.all` method now delivers named-tuple results
+The :meth:`.future.Result.all` method now delivers named-tuple results
in all cases, even for an ORM select that is against a single entity. This
is for consistency in the return type.
* Essentially, it is hoped that the re-architecting of :class:`.Connection`
to no longer support things like "autocommit" and "connectionless"
execution, as well as the changes to how result fetching will work with the
- ``InvocationContext`` which is hoped to be simpler in how it interacts with
+ ``Result`` which is hoped to be simpler in how it interacts with
the cursor, will make it **much easier** to build async versions of
SQLAlchemy's :class:`.Connection`. The simplified model of
``Connection.execute()`` and ``Session.execute()`` as the single point of