Start here
The safe first move
Use joinedload(...) with mapped attributes when the relationship path is obvious. Stop when aliasing or dotted paths make the replacement unclear.
Stop before automation when: Alias-heavy loading. Dotted paths tied to query shape.
Target shape
query = session.query(User).options(
joinedload(User.orders).joinedload(Order.items)
)
query = query.options(joinedload(User.addresses))