Some highlights are the with_polymorphic() Query method, which when
used with polymorphic inheritance, creates joins on the fly to
subclasses:
session.query(BaseClass).\
with_polymorphic([SubClass1, SubClass2]).\
filter(or_(SubClass1.attr=='somevalue',
SubClass2.attr=='somevalue'))
and its cousin, used with join(), has() and any(), which is known as
of_type():
session.query(Parent).\
join(Parent.elements.of_type(SubElement)).\
filter(SubElement.attr=='somevalue')
The new declarative layer is extremely small, and allows Schema and
MapperProperty constructs, which we usually recognize as Column and
relation() constructs, to be laid out inline with a class. The
underlying Table and mapper() are created behind the scenes as soon as
the class is complete, and are then available as cls.__mapper__ and
cls.__table__. Unlike the old ActiveMapper extension, "declarative"
aims to not redefine any existing SQLAlchemy semantics - it strictly
changes the order of steps to be joined within the class definition.
For example:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50))
addresses = relation("Address", backref="user")
class Address(Base):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True)
email = Column('email', String(50))
user_id = Column('user_id', Integer, ForeignKey('users.id'))
The declarative extension is documented in the "plugins" chapter of
the docs as well as within its module-level documentation.
Download SQLAlchemy 0.4.4 at: http://www.sqlalchemy.org/download.html
changelog:
0.4.4
------
- sql
- Can again create aliases of selects against textual FROM
clauses, [ticket:975]
- The value of a bindparam() can be a callable, in which case
it's evaluated at statement execution time to get the value.
- added exception wrapping/reconnect support to result set
fetching. Reconnect works for those databases that
raise a catchable data error during results
(i.e. doesn't work on MySQL) [ticket:978]
- implemented two-phase API for "threadlocal" engine,
via engine.begin_twophase(), engine.prepare()
[ticket:936]
- fixed bug which was preventing UNIONS from being cloneable,
[ticket:986]
- added "bind" keyword argument to insert(), update(),
delete() and DDL(). The .bind property is now assignable
on those statements as well as on select().
- Insert statements can now be compiled with extra "prefix"
words between INSERT and INTO, for vendor extensions like
MySQL's INSERT IGNORE INTO table.
- orm
- any(), has(), contains(), ~contains(), attribute level ==
and != now work properly with self-referential relations -
the clause inside the EXISTS is aliased on the "remote"
side to distinguish it from the parent table. This
applies to single table self-referential as well as
inheritance-based self-referential.
- repaired behavior of == and != operators at the relation()
level when compared against NULL for one-to-one
relations [ticket:985]
- fixed bug whereby session.expire() attributes were not
loading on an polymorphically-mapped instance mapped
by a select_table mapper.
- added query.with_polymorphic() - specifies a list
of classes which descend from the base class, which will
be added to the FROM clause of the query. Allows subclasses
to be used within filter() criterion as well as eagerly loads
the attributes of those subclasses.
- Your cries have been heard: removing a pending item from an
attribute or collection with delete-orphan expunges the item
from the session; no FlushError is raised. Note that if you
session.save()'ed the pending item explicitly, the
attribute/collection removal still knocks it out.
- session.refresh() and session.expire() raise an error when
called on instances which are not persistent within the session
- Fixed potential generative bug when the same Query was used
to generate multiple Query objects using join().
- fixed bug which was introduced in 0.4.3, whereby loading an
already-persistent instance mapped with joined table inheritance
would trigger a useless "secondary" load from its joined
table, when using the default "select" polymorphic_fetch.
This was due to attributes being marked as expired
during its first load and not getting unmarked from the
previous "secondary" load. Attributes are now unexpired
based on presence in __dict__ after any load or commit
operation succeeds.
- deprecated Query methods apply_sum(), apply_max(), apply_min(),
apply_avg(). Better methodologies are coming....
- relation() can accept a callable for its first argument,
which returns the class to be related. This is in place
to assist declarative packages to define relations without
classes yet being in place.
- Added a new "higher level" operator called "of_type()": used
in join() as well as with any() and has(), qualifies the
subclass which will be used in filter criterion, e.g.:
query.filter(Company.employees.of_type(Engineer).
any(Engineer.name=='foo'))
or
query.join(Company.employees.of_type(Engineer)).
filter(Engineer.name=='foo')
- Preventive code against a potential lost-reference bug in
flush().
- Expressions used in filter(), filter_by() and others, when
they make usage of a clause generated from a relation using
the identity of a child object (e.g.,
filter(Parent.child==<somechild>)), evaluate the actual
primary key value of <somechild> at execution time so that
the autoflush step of the Query can complete, thereby
populating the PK value of <somechild> in the case that
<somechild> was pending.
- setting the relation()-level order by to a column in the
many-to-many "secondary" table will now work with eager
loading, previously the "order by" wasn't aliased against
the secondary table's alias.
- Synonyms riding on top of existing descriptors are now
full proxies to those descriptors.
- dialects
- Invalid SQLite connection URLs now raise an error.
- postgres TIMESTAMP renders correctly [ticket:981]
- postgres PGArray is a "mutable" type by default;
when used with the ORM, mutable-style equality/
copy-on-write techniques are used to test for changes.
- extensions
- a new super-small "declarative" extension has been added,
which allows Table and mapper() configuration to take place
inline underneath a class declaration. This extension differs
from ActiveMapper and Elixir in that it does not redefine
any SQLAlchemy semantics at all; literal Column, Table
and relation() constructs are used to define the class
behavior and table definition.