summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/unreleased_12/4049.rst8
-rw-r--r--lib/sqlalchemy/orm/strategy_options.py2
-rw-r--r--test/orm/test_deferred.py38
-rw-r--r--test/orm/test_options.py29
4 files changed, 76 insertions, 1 deletions
diff --git a/doc/build/changelog/unreleased_12/4049.rst b/doc/build/changelog/unreleased_12/4049.rst
new file mode 100644
index 000000000..010d1a2c0
--- /dev/null
+++ b/doc/build/changelog/unreleased_12/4049.rst
@@ -0,0 +1,8 @@
+.. change::
+ :tags: bug, orm
+ :tickets: 4049
+
+ Fixed regression where the use of a :func:`.undefer_group` option
+ in conjunction with a lazy loaded relationship option would cause
+ an attribute error, due to a bug in the SQL cache key generation
+ added in 1.2 as part of :ticket:`3954`. \ No newline at end of file
diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py
index c47536a02..e07a6b3d0 100644
--- a/lib/sqlalchemy/orm/strategy_options.py
+++ b/lib/sqlalchemy/orm/strategy_options.py
@@ -110,7 +110,7 @@ class Load(Generative, MapperOption):
serialized.append(
(
tuple(serialized_path) +
- obj.strategy +
+ (obj.strategy or ()) +
(tuple([
(key, obj.local_opts[key])
for key in sorted(obj.local_opts)
diff --git a/test/orm/test_deferred.py b/test/orm/test_deferred.py
index 9295399bc..21f40a39a 100644
--- a/test/orm/test_deferred.py
+++ b/test/orm/test_deferred.py
@@ -387,6 +387,44 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest):
"FROM orders ORDER BY orders.id",
{})])
+ def test_undefer_group_from_relationship_lazyload(self):
+ users, Order, User, orders = \
+ (self.tables.users,
+ self.classes.Order,
+ self.classes.User,
+ self.tables.orders)
+
+ mapper(User, users, properties=dict(
+ orders=relationship(Order, order_by=orders.c.id)))
+ mapper(
+ Order, orders, properties=util.OrderedDict([
+ ('userident', deferred(orders.c.user_id, group='primary')),
+ ('description', deferred(orders.c.description,
+ group='primary')),
+ ('opened', deferred(orders.c.isopen, group='primary'))
+ ])
+ )
+
+ sess = create_session()
+ q = sess.query(User).filter(User.id == 7).options(
+ defaultload(User.orders).undefer_group('primary')
+ )
+
+ def go():
+ result = q.all()
+ o2 = result[0].orders[1]
+ eq_(o2.opened, 1)
+ eq_(o2.userident, 7)
+ eq_(o2.description, 'order 3')
+ self.sql_eq_(go, [
+ ("SELECT users.id AS users_id, users.name AS users_name "
+ "FROM users WHERE users.id = :id_1", {"id_1": 7}),
+ ("SELECT orders.user_id AS orders_user_id, orders.description "
+ "AS orders_description, orders.isopen AS orders_isopen, "
+ "orders.id AS orders_id, orders.address_id AS orders_address_id "
+ "FROM orders WHERE :param_1 = orders.user_id ORDER BY orders.id",
+ {'param_1': 7})])
+
def test_undefer_star(self):
orders, Order = self.tables.orders, self.classes.Order
diff --git a/test/orm/test_options.py b/test/orm/test_options.py
index 024806d42..44ebe81c3 100644
--- a/test/orm/test_options.py
+++ b/test/orm/test_options.py
@@ -1393,3 +1393,32 @@ class CacheKeyTest(PathTest, QueryTest):
)
)
+ def test_unbound_cache_key_undefer_group(self):
+ User, Address = self.classes('User', 'Address')
+
+ query_path = self._make_path_registry([User, "addresses"])
+
+ opt = defaultload(User.addresses).undefer_group('xyz')
+
+ eq_(
+ opt._generate_cache_key(query_path),
+
+ (
+ (Address, 'column:*', ("undefer_group_xyz", True)),
+ )
+ )
+
+ def test_bound_cache_key_undefer_group(self):
+ User, Address = self.classes('User', 'Address')
+
+ query_path = self._make_path_registry([User, "addresses"])
+
+ opt = Load(User).defaultload(User.addresses).undefer_group('xyz')
+
+ eq_(
+ opt._generate_cache_key(query_path),
+
+ (
+ (Address, 'column:*', ("undefer_group_xyz", True)),
+ )
+ )