.. changelog::
:version: 1.1.0b1
+ .. change::
+ :tags: change, orm
+ :tickets: 3394
+
+ The :paramref:`.Mapper.order_by` parameter is deprecated.
+ This is an old parameter no longer relevant to how SQLAlchemy
+ works, once the Query object was introduced. By deprecating it
+ we establish that we aren't supporting non-working use cases
+ and that we encourage applications to move off of the use of this
+ parameter.
+
+ .. seealso::
+
+ :ref:`change_3394`
+
.. change::
:tags: feature, postgresql
:ticket:`3512`
+.. _change_3394:
+
+Mapper.order_by is deprecated
+-----------------------------
+
+This old parameter from the very first versions of SQLAlchemy was part of
+the original design of the ORM which featured the :class:`.Mapper` object
+as a public-facing query structure. This role has long since been replaced
+by the :class:`.Query` object, where we use :meth:`.Query.order_by` to
+indicate the ordering of results in a way that works consistently for any
+combination of SELECT statements, entities and SQL expressions. There are
+many areas in which :paramref:`.Mapper.order_by` doesn't work as expected
+(or what would be expected is not clear), such as when queries are combined
+into unions; these cases are not supported.
+
+
+:ticket:`3394`
+
New Features and Improvements - Core
====================================
ordering for entities. By default mappers have no pre-defined
ordering.
+ .. deprecated:: 1.1 The :paramref:`.Mapper.order_by` parameter
+ is deprecated. Use :meth:`.Query.order_by` to determine the
+ ordering of a result set.
+
:param passive_deletes: Indicates DELETE behavior of foreign key
columns when a joined-table inheritance entity is being deleted.
Defaults to ``False`` for a base mapper; for an inheriting mapper,
if order_by is not False:
self.order_by = util.to_list(order_by)
+ util.warn_deprecated(
+ "Mapper.order_by is deprecated."
+ "Use Query.order_by() in order to affect the ordering of ORM "
+ "result sets.")
+
else:
self.order_by = order_by
m1 = mapper(A, table1, properties={
"bs": relationship(B, cascade="all, delete",
- order_by=table2.c.col1)},
- order_by=table1.c.col1)
+ order_by=table2.c.col1)})
m2 = mapper(B, table2)
m3 = mapper(A, table1, non_primary=True)
sess.flush()
sess.expunge_all()
- alist = sess.query(A).all()
+ alist = sess.query(A).order_by(A.col1).all()
eq_(
[
A(col2="a1", bs=[B(col2="b1"), B(col2="b2")]),
m1 = mapper(A, table1, properties={
"bs": relationship(B, cascade="all, delete",
order_by=table2.c.col1)},
- order_by=table1.c.col1,
_compiled_cache_size=10
)
m2 = mapper(B, table2,
sess.flush()
sess.expunge_all()
- alist = sess.query(A).all()
+ alist = sess.query(A).order_by(A.col1).all()
eq_(
[
A(col2="a1", bs=[B(col2="b1"), B(col2="b2")]),
@decl.declared_attr
def __mapper_args__(cls):
return {
- "order_by": cls.__table__.c.name
+ "primary_key": cls.__table__.c.id
}
decl.DeferredReflection.prepare(testing.db)
])
sess.commit()
eq_(
- sess.query(User).all(),
+ sess.query(User).order_by(User.name).all(),
[
User(name='A'),
User(name='C'),
with_polymorphic=person_with_polymorphic,
polymorphic_on=people.c.type,
polymorphic_identity='person',
- order_by=people.c.person_id,
properties={
'paperwork':relationship(
Paperwork,
backref=backref('prev', foreignkey=join.c.id, uselist=False),
uselist=False, primaryjoin=join.c.id==join.c.related_id),
'data':relationship(mapper(Data, data))
- },
- order_by=table1.c.id)
+ })
configure_mappers()
assert False
except:
backref=backref('prev', remote_side=table1.c.id, uselist=False),
uselist=False, primaryjoin=table1.c.id==table1.c.related_id),
'data':relationship(mapper(Data, data), lazy='joined', order_by=data.c.id)
- },
- order_by=table1.c.id
+ }
)
table1b_mapper = mapper(Table1B, inherits=table1_mapper, polymorphic_identity='table1b')
# clear and query forwards
sess.expunge_all()
- node = sess.query(Table1).filter(Table1.id==t.id).first()
+ node = sess.query(Table1).order_by(Table1.id).\
+ filter(Table1.id==t.id).first()
assertlist = []
while (node):
assertlist.append(node)
# clear and query backwards
sess.expunge_all()
- node = sess.query(Table1).filter(Table1.id==obj.id).first()
+ node = sess.query(Table1).order_by(Table1.id).\
+ filter(Table1.id==obj.id).first()
assertlist = []
while (node):
assertlist.insert(0, node)
sess = create_session()
def go():
- eq_(sess.query(Person).all(), all_employees)
+ eq_(
+ sess.query(Person).order_by(Person.person_id).all(),
+ all_employees)
count = {'':14, 'Polymorphic':9}.get(self.select_type, 10)
self.assert_sql_count(testing.db, go, count)
sess = create_session()
def go():
- eq_(sess.query(Person)
+ eq_(sess.query(Person).order_by(Person.person_id)
.options(joinedload(Engineer.machines))[1:3],
all_employees[1:3])
count = {'':6, 'Polymorphic':3}.get(self.select_type, 4)
def test_primary_eager_aliasing_two(self):
sess = create_session()
def go():
- eq_(sess.query(Person)
+ eq_(sess.query(Person).order_by(Person.person_id)
.options(subqueryload(Engineer.machines)).all(),
all_employees)
count = {'':14, 'Polymorphic':7}.get(self.select_type, 8)
sess = create_session()
def go():
eq_(sess.query(Person).with_polymorphic('*')
+ .order_by(Person.person_id)
.options(joinedload(Engineer.machines))[1:3],
all_employees[1:3])
self.assert_sql_count(testing.db, go, 3)
def test_join_from_polymorphic_nonaliased_two(self):
sess = create_session()
eq_(sess.query(Person)
+ .order_by(Person.person_id)
.join('paperwork', aliased=False)
.filter(Paperwork.description.like('%#2%')).all(),
[e1, m1])
def test_join_from_polymorphic_nonaliased_three(self):
sess = create_session()
eq_(sess.query(Engineer)
+ .order_by(Person.person_id)
.join('paperwork', aliased=False)
.filter(Paperwork.description.like('%#2%')).all(),
[e1])
def test_join_from_polymorphic_nonaliased_four(self):
sess = create_session()
eq_(sess.query(Person)
+ .order_by(Person.person_id)
.join('paperwork', aliased=False)
.filter(Person.name.like('%dog%'))
.filter(Paperwork.description.like('%#2%')).all(),
def test_join_from_polymorphic_aliased_one(self):
sess = create_session()
eq_(sess.query(Person)
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Paperwork.description.like('%review%')).all(),
[b1, m1])
def test_join_from_polymorphic_aliased_two(self):
sess = create_session()
eq_(sess.query(Person)
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Paperwork.description.like('%#2%')).all(),
[e1, m1])
def test_join_from_polymorphic_aliased_three(self):
sess = create_session()
eq_(sess.query(Engineer)
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Paperwork.description.like('%#2%')).all(),
[e1])
def test_join_from_polymorphic_aliased_four(self):
sess = create_session()
eq_(sess.query(Person)
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Person.name.like('%dog%'))
.filter(Paperwork.description.like('%#2%')).all(),
sess = create_session()
eq_(sess.query(Person)
.with_polymorphic(Manager)
+ .order_by(Person.person_id)
.join('paperwork')
.filter(Paperwork.description.like('%review%')).all(),
[b1, m1])
sess = create_session()
eq_(sess.query(Person)
.with_polymorphic([Manager, Engineer])
+ .order_by(Person.person_id)
.join('paperwork')
.filter(Paperwork.description.like('%#2%')).all(),
[e1, m1])
sess = create_session()
eq_(sess.query(Person)
.with_polymorphic([Manager, Engineer])
+ .order_by(Person.person_id)
.join('paperwork')
.filter(Person.name.like('%dog%'))
.filter(Paperwork.description.like('%#2%')).all(),
sess = create_session()
eq_(sess.query(Person)
.with_polymorphic([Manager, Engineer])
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Paperwork.description.like('%#2%')).all(),
[e1, m1])
sess = create_session()
eq_(sess.query(Person)
.with_polymorphic([Manager, Engineer])
+ .order_by(Person.person_id)
.join('paperwork', aliased=True)
.filter(Person.name.like('%dog%'))
.filter(Paperwork.description.like('%#2%')).all(),
sess = create_session()
any_ = Engineer.machines.any(
Machine.name == "Commodore 64")
- eq_(sess.query(Person).filter(any_).all(), [e2, e3])
+ eq_(
+ sess.query(Person).order_by(Person.person_id).filter(any_).all(),
+ [e2, e3])
def test_polymorphic_any_nine(self):
sess = create_session()
any_ = Person.paperwork.any(
Paperwork.description == "review #2")
- eq_(sess.query(Person).filter(any_).all(), [m1])
-
+ eq_(
+ sess.query(Person).order_by(Person.person_id).filter(any_).all(),
+ [m1])
def test_join_from_columns_or_subclass_one(self):
sess = create_session()
sess = create_session()
def go():
eq_(sess.query(Person)
- .with_polymorphic('*').all(),
+ .with_polymorphic('*').order_by(Person.person_id).all(),
self._emps_wo_relationships_fixture())
self.assert_sql_count(testing.db, go, 1)
sess = create_session()
# compare to entities without related collections to prevent
# additional lazy SQL from firing on loaded entities
- eq_(sess.query(Person).with_polymorphic('*').all(),
+ eq_(sess.query(Person).with_polymorphic('*').
+ order_by(Person.person_id).all(),
self._emps_wo_relationships_fixture())
def test_filter_on_baseclass(self):
sess = create_session()
- eq_(sess.query(Person).all(), all_employees)
- eq_(sess.query(Person).first(), all_employees[0])
- eq_(sess.query(Person)
+ eq_(sess.query(Person).order_by(Person.person_id).all(), all_employees)
+ eq_(
+ sess.query(Person).order_by(Person.person_id).first(),
+ all_employees[0])
+ eq_(sess.query(Person).order_by(Person.person_id)
.filter(Person.person_id == e2.person_id).one(),
e2)
sess = create_session()
palias = aliased(Person)
eq_(sess.query(palias)
+ .order_by(palias.person_id)
.filter(palias.name.in_(['dilbert', 'wally'])).all(),
[e1, e2])
'Elbonia, Inc.')]
eq_(sess.query(Engineer, Company.name)
.join(Company.employees)
+ .order_by(Person.person_id)
.filter(Person.type == 'engineer').all(),
expected)
palias = aliased(Person)
self.assert_compile(
sess.query(palias, Company.name)
+ .order_by(palias.person_id)
.join(Person, Company.employees)
.filter(palias.name == 'dilbert'),
"SELECT anon_1.people_person_id AS anon_1_people_person_id, "
self.assert_compile(
sess.query(palias, Company.name)
.select_from(palias)
+ .order_by(palias.person_id)
.join(Person, Company.employees)
.filter(palias.name == 'dilbert'),
"SELECT people_1.person_id AS people_1_person_id, "
mapper(Keyword, keywords)
mapper(KeywordAssociation, item_keywords, properties={
'keyword':relationship(Keyword, lazy='joined')},
- primary_key=[item_keywords.c.item_id, item_keywords.c.keyword_id],
- order_by=[item_keywords.c.data])
+ primary_key=
+ [item_keywords.c.item_id, item_keywords.c.keyword_id])
mapper(Item, items, properties={
'keywords' : relationship(KeywordAssociation,
+ order_by=item_keywords.c.data,
cascade="all, delete-orphan")
})
Order, orders = self.classes.Order, self.tables.orders
- mapper(Order, orders, order_by=orders.c.id, properties={
+ mapper(Order, orders, properties={
'description': deferred(orders.c.description)})
o = Order()
self.assert_(o.description is None)
- q = create_session().query(Order)
+ q = create_session().query(Order).order_by(Order.id)
def go():
l = q.all()
o2 = l[2]
Order, orders = self.classes.Order, self.tables.orders
- mapper(Order, orders, order_by=orders.c.id, properties={
+ mapper(Order, orders, properties={
'id': deferred(orders.c.id)})
# right now, it's not that graceful :)
orders, Order = self.tables.orders, self.classes.Order
- mapper(Order, orders, order_by=orders.c.id, properties=dict(
+ mapper(Order, orders, properties=dict(
description=deferred(orders.c.description, group='primary'),
opened=deferred(orders.c.isopen, group='primary')))
def test_unsaved_group_2(self):
orders, Order = self.tables.orders, self.classes.Order
- mapper(Order, orders, order_by=orders.c.id, properties=dict(
+ mapper(Order, orders, properties=dict(
description=deferred(orders.c.description, group='primary'),
opened=deferred(orders.c.isopen, group='primary')))
def test_load_only_subclass(self):
s = Session()
- q = s.query(Manager).options(load_only("status", "manager_name"))
+ q = s.query(Manager).order_by(Manager.person_id).\
+ options(load_only("status", "manager_name"))
self.assert_compile(
q,
"SELECT managers.person_id AS managers_person_id, "
"managers.manager_name AS managers_manager_name "
"FROM people JOIN managers "
"ON people.person_id = managers.person_id "
- "ORDER BY people.person_id"
+ "ORDER BY managers.person_id"
)
def test_load_only_subclass_and_superclass(self):
s = Session()
- q = s.query(Boss).options(load_only("status", "manager_name"))
+ q = s.query(Boss).order_by(Person.person_id).\
+ options(load_only("status", "manager_name"))
self.assert_compile(
q,
"SELECT managers.person_id AS managers_person_id, "
def test_load_only_alias_subclass(self):
s = Session()
m1 = aliased(Manager, flat=True)
- q = s.query(m1).options(load_only("status", "manager_name"))
+ q = s.query(m1).order_by(m1.person_id).\
+ options(load_only("status", "manager_name"))
self.assert_compile(
q,
"SELECT managers_1.person_id AS managers_1_person_id, "
"managers_1.manager_name AS managers_1_manager_name "
"FROM people AS people_1 JOIN managers AS "
"managers_1 ON people_1.person_id = managers_1.person_id "
- "ORDER BY people_1.person_id"
+ "ORDER BY managers_1.person_id"
)
def test_load_only_subclass_from_relationship_polymorphic(self):
# exclude the primary key
s = Session()
- q = s.query(Manager).options(
+ q = s.query(Manager).order_by(Person.person_id).options(
defer(".*"), undefer("status"))
self.assert_compile(
q,
def test_defer_super_name_on_subclass(self):
s = Session()
- q = s.query(Manager).options(defer("name"))
+ q = s.query(Manager).order_by(Person.person_id).options(defer("name"))
self.assert_compile(
q,
"SELECT managers.person_id AS managers_person_id, "
mapper(Node, nodes, properties={
'children': relationship(Node, lazy='select', order_by=nodes.c.id)
- }, order_by=nodes.c.id)
+ })
sess = create_session()
n1 = Node(data='n1')
n1.append(Node(data='n11'))
def go():
d = sess.query(Node).filter_by(data='n1').\
+ order_by(Node.id).\
options(joinedload('children.children')).first()
eq_(Node(data='n1', children=[
Node(data='n11'),
self.assert_sql_count(testing.db, go, 2)
def go():
- sess.query(Node).filter_by(data='n1').\
+ sess.query(Node).order_by(Node.id).filter_by(data='n1').\
options(joinedload('children.children')).first()
# test that the query isn't wrapping the initial query for eager
options(joinedload('addresses')).first(),
User(name='jack', addresses=[Address(id=1)]))
+ @testing.uses_deprecated("Mapper.order_by")
def test_join_mapper_order_by(self):
"""test that mapper-level order_by is adapted to a selectable."""
mapper(Person, people,
polymorphic_on=people.c.type,
polymorphic_identity='person',
- order_by=people.c.person_id,
properties={
'paperwork':relationship(Paperwork, order_by=paperwork.c.paperwork_id)
})
self.assert_compile(
sess.query(Person).with_polymorphic(Manager).
+ order_by(Person.person_id).
join('paperwork').filter(Paperwork.description.like('%review%')),
"SELECT people.person_id AS people_person_id, people.company_id AS"
" people_company_id, "
self.assert_compile(
sess.query(Person).with_polymorphic(Manager).
+ order_by(Person.person_id).
join('paperwork', aliased=True).
filter(Paperwork.description.like('%review%')),
"SELECT people.person_id AS people_person_id, people.company_id AS people_company_id, "
eq_(l, [self.static.user_result[0]])
+ @testing.uses_deprecated("Mapper.order_by")
def test_cancel_order_by(self):
users, User = self.tables.users, self.classes.User
users.c.id == addresses.c.user_id,
group_by=[c for c in users.c]).alias('myselect')
- mapper(User, s, order_by=s.c.id)
+ mapper(User, s)
sess = create_session()
- l = sess.query(User).all()
+ l = sess.query(User).order_by(s.c.id).all()
for idx, total in enumerate((14, 16)):
eq_(l[idx].concat, l[idx].id * 2)
items=relationship(Item, order_items,
order_by=items.c.id)))
- mapper(User, users, order_by=users.c.id, properties=dict(
+ mapper(User, users, properties=dict(
orders=relationship(Order, order_by=orders.c.id)))
def test_deep_options_1(self):
sess = create_session()
# joinedload nothing.
- u = sess.query(User).all()
+ u = sess.query(User).order_by(User.id).all()
def go():
u[0].orders[1].items[0].keywords[1]
sess = create_session()
l = (sess.query(User).
+ order_by(User.id).
options(sa.orm.joinedload_all('orders.items.keywords'))).all()
def go():
# same thing, with separate options calls
q2 = (sess.query(User).
+ order_by(User.id).
options(sa.orm.joinedload('orders')).
options(sa.orm.joinedload('orders.items')).
options(sa.orm.joinedload('orders.items.keywords')))
# joinedload "keywords" on items. it will lazy load "orders", then
# lazy load the "items" on the order, but on "items" it will eager
# load the "keywords"
- q3 = sess.query(User).options(
+ q3 = sess.query(User).order_by(User.id).options(
sa.orm.joinedload('orders.items.keywords'))
u = q3.all()
self.sql_count_(2, go)
sess = create_session()
- q3 = sess.query(User).options(
+ q3 = sess.query(User).order_by(User.id).options(
sa.orm.joinedload(User.orders, Order.items, Item.keywords))
u = q3.all()
mapper(Port, port)
mapper(Jack, jack,
- order_by=[jack.c.number],
properties=dict(
port=relationship(Port, backref='jack',
uselist=False,
mapper(
Container,
container_select,
- order_by=sa.asc(container_select.c.type),
properties=dict(
lineItems=relationship(
LineItem,
session.add(li)
session.flush()
session.expunge_all()
- newcon = session.query(Container).first()
+ newcon = session.query(Container).\
+ order_by(container_select.c.type).first()
assert con.policyNum == newcon.policyNum
assert len(newcon.lineItems) == 10
for old, new in zip(con.lineItems, newcon.lineItems):
l = q.order_by(sa.desc(User.id)).limit(2).offset(2).all()
eq_(list(reversed(self.static.user_all_result[0:2])), l)
+ @testing.uses_deprecated("Mapper.order_by")
def test_mapper_order_by(self):
users, User, Address, addresses = (self.tables.users,
self.classes.User,
mapper(Node, nodes, properties={
'children':relationship(Node, order_by=nodes.c.id)
- }, order_by=nodes.c.id)
+ })
sess = create_session()
n1 = Node(data='n1')
n1.append(Node(data='n11'))
sess.flush()
sess.expunge_all()
def go():
- d = sess.query(Node).filter_by(data='n1').\
+ d = sess.query(Node).filter_by(data='n1').order_by(Node.id).\
options(subqueryload_all('children.children')).first()
eq_(Node(data='n1', children=[
Node(data='n11'),
session.flush()
assert assoc.count().scalar() == 0
+
class BooleanColTest(fixtures.MappedTest):
@classmethod
def define_tables(cls, metadata):
- Table('t1_t', metadata,
- Column('id', Integer, primary_key=True, test_needs_autoincrement=True),
+ Table(
+ 't1_t', metadata,
+ Column(
+ 'id', Integer,
+ primary_key=True, test_needs_autoincrement=True),
Column('name', String(30)),
Column('value', sa.Boolean))
# use the regular mapper
class T(fixtures.ComparableEntity):
pass
- orm_mapper(T, t1_t, order_by=t1_t.c.id)
+ orm_mapper(T, t1_t)
sess = create_session()
t1 = T(value=True, name="t1")
for clear in (False, True):
if clear:
sess.expunge_all()
- eq_(sess.query(T).all(), [T(value=True, name="t1"), T(value=False, name="t2"), T(value=True, name="t3")])
+ eq_(
+ sess.query(T).order_by(T.id).all(),
+ [
+ T(value=True, name="t1"),
+ T(value=False, name="t2"), T(value=True, name="t3")])
if clear:
sess.expunge_all()
- eq_(sess.query(T).filter(T.value==True).all(), [T(value=True, name="t1"),T(value=True, name="t3")])
+ eq_(
+ sess.query(T).filter(T.value == True).order_by(T.id).all(),
+ [T(value=True, name="t1"), T(value=True, name="t3")])
if clear:
sess.expunge_all()
- eq_(sess.query(T).filter(T.value==False).all(), [T(value=False, name="t2")])
+ eq_(
+ sess.query(T).filter(T.value == False).order_by(T.id).all(),
+ [T(value=False, name="t2")])
t2 = sess.query(T).get(t2.id)
t2.value = True
sess.flush()
- eq_(sess.query(T).filter(T.value==True).all(), [T(value=True, name="t1"), T(value=True, name="t2"), T(value=True, name="t3")])
+ eq_(
+ sess.query(T).filter(T.value == True).order_by(T.id).all(),
+ [
+ T(value=True, name="t1"),
+ T(value=True, name="t2"), T(value=True, name="t3")])
t2.value = False
sess.flush()
- eq_(sess.query(T).filter(T.value==True).all(), [T(value=True, name="t1"),T(value=True, name="t3")])
+ eq_(
+ sess.query(T).filter(T.value == True).order_by(T.id).all(),
+ [T(value=True, name="t1"), T(value=True, name="t3")])
class RowSwitchTest(fixtures.MappedTest):