Query loading options incorrectly evaluated against children

Issue #2098 resolved
Former user created an issue

Script attached that crashes against both 0.6.6 and 0.7b2.

Quick version: I have a mapped object a, with chains of relations a.b and a.c.d. The table mapped by a.b also has a column c. When I queried for a, I used joinedload('c.d'), expecting this to do a joined load on a.c.d when I triggered the lazy loading of a.c.

However, when lazy loading a.b, SQLAlchemy tries to evaluate the 'c.d' string. a.b.c exists, so SQLAlchemy tries to find d, and at that point crashes because a.b.c is a column, not a mapper.

I can't find any documentation to suggest that loading options are anchored against ''every'' relation ultimately attached to the original query; my impression was that they were rooted only to the query's entities. Either way, this should surely not crash.

Stack trace:

Traceback (most recent call last):
  File "sqla-broken-joinedload.py", line 67, in <module>
    print a.b
  File ".../sqlalchemy/orm/attributes.py", line 162, in __get__
    return self.impl.get(instance_state(instance),dict_)
  File ".../sqlalchemy/orm/attributes.py", line 414, in get
    value = self.callable_(state, passive)
  File ".../sqlalchemy/orm/strategies.py", line 517, in _load_for_state
    q = q._conditional_options(*state.load_options)
  File ".../sqlalchemy/orm/query.py", line 884, in _conditional_options
    return self._options(True, *args)
  File "<string>", line 1, in <lambda>
  File ".../sqlalchemy/orm/query.py", line 52, in generate
    fn(self, *args[1:](1:), **kw)
  File ".../sqlalchemy/orm/query.py", line 895, in _options
    opt.process_query_conditionally(self)
  File ".../sqlalchemy/orm/interfaces.py", line 394, in process_query_conditionally
    self._process(query, False)
  File ".../sqlalchemy/orm/interfaces.py", line 397, in _process
    paths, mappers = self._get_paths(query, raiseerr)
  File ".../sqlalchemy/orm/interfaces.py", line 472, in _get_paths
    if mapper.has_property(token):
AttributeError: 'NoneType' object has no attribute 'has_property'

Comments (5)

  1. Mike Bayer repo owner
    • changed milestone to 0.6.7

    It's always a better idea to use object attributes, thereby removing any ambiguity:

        a, = sess.query(A).options(
            joinedload(A.c, AC.d),
        ).all()
    

    the mis-representation of 'c.d' as living on AB is a bug.

  2. Former user Account Deleted

    Aha, I'd forgotten I could do that. That certainly solves my immediate problem; thanks!

  3. Log in to comment