On Wed, Sep 23, 2020, at 4:17 PM, agrot...@gmail.com wrote:
> I actually don't really care that much to have the attribute remain dynamic. 
> In fact there is only one *specific* filtering that I want to apply to it, 
> but that filtering will vary from (web) request to (web) request. This is 
> what made me think of using contains_eager.
> 
> Right now this is the best solution I have come up with, which is to define a 
> temporary class that extends A and add to that class a new relationship with 
> the custom filter applied. I then specify to selectinload that property. Is 
> there a better way to do this?

I would still use a separate relationship on the same class, you can always 
make a @hybrid_property that switches between the two relationships depending 
on what you want to do.

In version 1.4, which will be in betas as soon as I can get a huge amount of 
new docs written, you will have a potentially better option for this which is 
the PropComparator.and_() operator.  you can play with this now from git master 
if you were interested:

https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#adding-criteria-to-loader-options

that way you'd say:

session.query(A).options(selectinload(A.bs).and_(B.some_field == value))

that might be what you're waiting for here


> 
> # Run this code for each web request, reading some_field_value from the value 
> the client specifies in the request:
> some_field_value = ...
> 
> class ATmp(A):
>     bs_temp = relationship(
>         lambda: models.B,
>         primaryjoin=(
>             (models.A.id == models.B.a_id)
>             & (models.B.some_field == some_field_value)
>         ),
>     )
> 
> q = return db.session.query(ATmp).options(selectinload(cls.bs_temp))
> # iterate over the q (which in iterable of "A"s) and for each A, iterate over 
> the bs_temp, which is a filtered collection of Bs.
> 
> This also leads to a warning:
> SAWarning: This declarative base already contains a class with the same class 
> name and module name as my_app.graphql.queries.ATmp, and will be replaced in 
> the string-lookup table
> 
> though it does seem to work (I am able to avoid n+1 and do the filtering in 
> the DB).
> On Wednesday, September 23, 2020 at 8:10:44 AM UTC-4 Mike Bayer wrote:
>> 
>> 
>> On Wed, Sep 23, 2020, at 5:43 AM, agrot...@gmail.com wrote:
>>> Let's say I have a model with a one to many relationship as such:
>>> class A(Base):
>>> id = ...
>>> 
>>> class B(Base):
>>> id = ...
>>> some_field = ....
>>> a_id = Column(ForeignKey(A.id)...
>>> a = relationship(A, backref=backref('bs', lazy='dynamic'))
>>> 
>>> I can define a method on A:
>>> class A(Base):
>>> ...
>>> def get_b_with_some_field(self, some_field):
>>> return self.bs.filter(B.some_field==some_field)
>>> 
>>> to get all b's that have a certain value of `some_field`.
>>> 
>>> Is there any way to accomplish this with eager fetching to avoid the n+1 
>>> select problem that will occur if I want to query for a lot of `A`s and 
>>> then iterate over the collection and for each call `get_b_with_some_field` 
>>> with the same value of `some_field`?'
>> 
>> if you want to have that attribute remain on "dynamic" then you'd need to 
>> define a second relationship where you can use normal eager fetching 
>> strategies, and then use that for those cases.
>> 
>> IMO "dynamic" is not really worth it, you can get the same queries more 
>> programmatically by using query(B).filter(with_parent(some_a, A.bs)).
>> 
>> 
>> 
>> 
>> 
>>> 
>>> 
>>> One option is to to change relationship to from `lazy='dynamic'` to 
>>> `lazy='subquery'` or ``lazy='selectin'`` and then implement the filtering 
>>> in `get_b_with_some_field` in Python. This will address the n+1 select 
>>> problem, but will cause pulling extra data from the database (and extra 
>>> work in Python).
>>> 
>>> I thought `contains_eager` 
>>> <https://docs.sqlalchemy.org/en/13/orm/loading_relationships.html?highlight=contains_eager#using-contains-eager-to-load-a-custom-filtered-collection-result>
>>>  might be relevant; however, I only see it being mentioned in the case of 
>>> joined loads.
>>> 
>>> The reason I am looking for this functionality is I am defining a graphql 
>>> API that looks like the following:
>>> type query {
>>> as: [A!!
>>> }
>>> 
>>> type A {
>>>     ...
>>> bs(some_field: String): [B!]!
>>> }
>>> 
>>> type B {
>>>     ...
>>> some_field: String!
>>> }
>>> where I would like to be able to specify a filter on the `bs` relationship 
>>> from `A`. I would ideally like to 1. avoid the n+1 select issue and 2. 
>>> perform the some_field filtering at the database level, and 3. leverage as 
>>> much of the ORM as possible ;-)
>>> 
>>> Is it possible to do this within SQLA?
>>> 

>>> --
>>> 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+...@googlegroups.com.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/sqlalchemy/55c7b3a6-bfee-45b6-83bc-25185bf7af87n%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/sqlalchemy/55c7b3a6-bfee-45b6-83bc-25185bf7af87n%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/e20cd72d-796f-4e99-a91d-55f4252f5fd6n%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/e20cd72d-796f-4e99-a91d-55f4252f5fd6n%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/70d3ec56-d998-4e14-9412-57fbdc409ad1%40www.fastmail.com.

Reply via email to