the recursion_depth feature on selectinload() is also very new and that is actually a very complex and not very mature feature. If you only wanted to apply additional options for N levels deep, you would build out separate options for that, like:
options( selectinload(Model.thing, recursion_depth=-1), defaultload(Model.thing).selectinload(Model.otherthing).selectinload(Model.otherthing) ) something like that again, fairly esoteric stuff On Fri, Sep 15, 2023, at 4:25 AM, Cornelis Poppema wrote: > Hello Mike, thank you very much for the in-depth reply and providing a > solution :) > > There is no specific reason that I posted in google groups, I did not visit > the support page, this was just something I decided after thinking where to > post first between googlegroups and stackoverflow, I will use github > discussions when I open a new discussion in the future! > Your workaround will help me continue so many many thanks. I thought I tried > all variations, but I can only concede after seeing this work that I did not > attempt adding the selectinload to the root options(). > > It might warrant a new thread, but can you also tell me if there is a way to > control the options() that sqlalchemy uses for the recursion of next_step ? > > Ie. I included this bit in the original post: > ``` > .options( > selectinload(StepModel.next_step, recursion_depth=-1), > ... > ) > ``` > > and it would be helpful to know if I can chain the same options to next_step, > so that step also has its actions and their relationships() eagerly available > etc. > > PS > FWIW the reason I included `raiseload("*")` in options() is because I am > running async queries, and personally the error I will be confronted with > trying to access lazy attributes is more helpful, so I've come to add it by > default. Without raisedload(*) I would see: > ``` > sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't > call await_only() here. Was IO attempted in an unexpected place? (Background > on this error at: https://sqlalche.me/e/20/xd2s) > ``` > > With the help of raisedload(*) I get to see: > ``` > sqlalchemy.exc.InvalidRequestError: 'ServiceActionModel.service' is not > available due to lazy='raise``` > ``` > > This helps me tackle those cases more easily one-by-one. > > On Thursday, 14 September 2023 at 15:30:23 UTC+2 Mike Bayer wrote: >> __ >> >> >> On Thu, Sep 14, 2023, at 7:36 AM, Cornelis Poppema wrote: >>> Hi all, >>> >>> I am new to sqlalchemy, I think the idea of what I am trying to achieve is >>> relatively simple, but I can't seem to figure out how to retrieve >>> `.service` in the same query. I failed to find an example in the 2.0 >>> documentation for exactly this. >>> >>> My attempts have been to simply chain a .selectinload after the >>> .selectin_polymorphic, ie.: >>> >>> ```python >>> .options( >>> selectinload(StepModel.next_step, recursion_depth=-1), >>> selectinload(StepModel.actionbases).selectin_polymorphic( >>> [ >>> ServiceActionModel, >>> ], >>> ) >>> .selectinload(ServiceActionModel.service), >>> raiseload("*"), >>> ) >>> ``` >>> >>> This gives the error: >>> >>> ``` >>> /usr/local/lib/python3.11/site-packages/sqlalchemy/orm/strategy_options.py:2442: >>> in _raise_for_does_not_link >>> raise sa_exc.ArgumentError( >>> E sqlalchemy.exc.ArgumentError: ORM mapped entity or attribute >>> "ServiceActionModel.service" does not link from relationship >>> "StepModel.actionbases". Did you mean to use >>> "StepModel.actionbases.of_type(ServiceActionModel)"? >>> ``` >>> >> >> Hi - >> >> A few up front things, is it possible you can post these questions that have >> a lot of code on github discussions? That's at >> https://github.com/sqlalchemy/sqlalchemy/discussions . I'm sort of >> wondering how new users are still arriving here at the mailing list, did you >> find this list via the support page at >> https://www.sqlalchemy.org/support.html ? I would want to change the >> verbiage there to please refer people to GH discussions instead. >> Especially with these advanced inheritance eager loading problems, which in >> the majority of cases end up being real bugs in SQLAlchemy, as seems to be >> the case here (at least, there is an inconsistency in the API that somehow >> needs to be documented, or something). >> >> As for the question, first off this is really advanced usage and I've hardly >> ever seen people using selectin_polymorphic(), much less deep within a chain >> of loaders like this. >> >> The correct form for this load would follow from how it's described at >> https://docs.sqlalchemy.org/en/20/orm/queryguide/inheritance.html#combining-additional-loader-options-with-selectin-polymorphic-subclass-loads >> , where the ORM allows the selectin_polymorphic(Target, [TargetSubclassA]) >> to be a sibling to the appropriate relationship load, >> selectinload(TargetSubclassA.elements). The example there places both of >> these options comma-separated within select().options(). This is the >> "inconsistent" part because I'm already surprised the ORM is allowing the >> selectinload() to be present against TargetSubclassA when that's not one of >> the primary entities in the select(). >> >> However in your case, you are coming off of a parent loader option already. >> So following from this, the correct form based on a direct reading of those >> docs would, *in theory*, be: >> >> select().options( >> selectinload(Parent.target).options( >> selectin_polymorphic(Target, [TargetSubclassA]), >> selectinload(TargetSubclassA.elements) >> ) >> ) >> >> that is, you can build up sibling options from a parent loader option using >> another call to .options(). >> >> however, this doesn't work; the validation of the loader chain >> unsurprisingly notes that TargetSubclass is not linked from Parent.target, >> and they'd like you to use of_type() instead. So I've made a bug for this >> here: https://github.com/sqlalchemy/sqlalchemy/issues/10348 as something >> has to change here, either the docs, or the usage pattern for >> selectin_polymorphic(), or the error checks have to get a lot smarter to >> figure this out and let this case pass, since it works fine the way you are >> expecting if I just have it skip the error checking. >> >> What you can do now is use with_polymorphic() instead that is more >> configurable for this kind of loader chain: >> >> TT = with_polymorphic(Target, [TargetSubclassA]) >> select().options(selectinload(Parent.target.of_type(TT).selectinload(TT.TargetSubclassA.elements))) >> >> discussion can continue at the issue above or a new github discussion, >> thanks! >> >> > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sqlalchemy/3e4b053f-e583-4a20-98b5-abfd08479b60n%40googlegroups.com > > <https://groups.google.com/d/msgid/sqlalchemy/3e4b053f-e583-4a20-98b5-abfd08479b60n%40googlegroups.com?utm_medium=email&utm_source=footer>. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/95767929-f049-470d-ae36-7efe0a456791%40app.fastmail.com.