Skip to content

deprecate noload() option #11045

Closed
Closed

Description

@zzzeek

this option was added as kind of a one-off about 18 years ago to suit an example case for custom loading of relationships which I'd never recommend today. because the option turns off the related attribute entirely, it has all kinds of not easily predictable behaviors, it returns essentially incorrect results (e.g. None when there would normally be a collection there) and we continue to get complaints about other features not working when it's used e.g. #11040.

The one place people use this is when they have some kind of serializer that touches every attribute and they dont want an attribute to load. I think that's a bad use case. They should do one of 1. dont have that relationship there if it isnt part of the object's state 2. get a serializer that can select for which attributes you want to serialize and which you dont 3. eagerly load the collection there. it's no different from an object with a relationship that has a huge list of related objects already loaded and you don't want to serialize that either.

so let's just deprecate it and we dont have to deal with complaints anymore, people will write better programs.

Activity

  1. added this to the 2.1 milestone on Feb 21, 2024
  2. sqla-tester commented on Jan 24, 2025

    @sqla-tester
    Collaborator

    Federico Caselli has proposed a fix for this issue in the main branch:

    The noload loader option is now deprecated. https://gerrit.sqlalchemy.org/c/sqlalchemy/sqlalchemy/+/5670

  3. Otto-AA commented on Mar 23, 2026

    @Otto-AA

    Can we work around this by using raiseload with try-except clauses?

    # previously noload('*'); (pseudo-code not tested)
    user = session.execute(select(User).options(raiseload('*'))).scalar_one()
    try:
      contacts = user.contacts
    except InvalidRequestError:
      contacts = None

    So that we can access user.contacts if it's eagerly loaded and get None if it's not explicitly eagerly loaded?

    They should [...] 2. get a serializer that can select for which attributes you want to serialize and which you dont

    In a project I work on, noload('*') + selectinload(...)' is the means to select which attributes get serialized: Different queries of Userwill specifynoload('*')with differentselectinload(User.contacts)orselectinload(User.biography), etc. And the result is converted to a domain model by a common map_user_to_domain_model(user), which tries to convert all relations that are not None` to dataclasses.

    Maybe not the best use case and this deprecation could be a reason to move away from this model. But I'd appreciate to have a workaround as this would require us to completely redesign our domain models (and all the functions using them, how the data is passed around, etc.). In our case much more effort than the 1.4 -> 2.0 migration.

    people will write better programs

    🙏 (the type checker would also be happy about this change :)

  4. CaselIT commented on Mar 23, 2026

    @CaselIT
    Member

    That should work, but if you prefer LBYL instead of EAFP you can use https://docs.sqlalchemy.org/en/20/orm/internals.html#sqlalchemy.orm.InstanceState.unloaded to check if a relationship is loaded or not.

    Something like

    def serialize(obj):
        ... # serialize scalar attrs
        state = sa.inspect(obj)
        loaded_relations = state.unloaded.symmetric_difference(state.mapper.relationships.keys()) 
        ... serialize loaded relationships
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingorm

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions