Yep, it totally makes sense. When it comes to the question you suggested,
it seems to me misleading that query parameters may affect further queries.
On the other hand, I understand that there are some optimizations in 
sqlalchemy
which may cause behavior such as this.

That's why I am not sure if options are intended to work per query or per 
session
(or maybe it's not specified).

W dniu poniedziałek, 15 października 2018 15:27:38 UTC+2 użytkownik Simon 
King napisał:
>
> This is an interesting question. Here's my explanation of what's going on: 
>
> When you run a query using a loader option such as raiseload, 
> SQLAlchemy constructs your instance and attaches the "raiseload" 
> behaviour to that instance. In your test_1, this happens, but since 
> you don't store the result, it is immediately garbage collected. You 
> then run a second query, *without* the raiseload option, so SQLAlchemy 
> constructs a second instance and doesn't trigger an exception when you 
> access the "bs" property. 
>
> In test_2, you save the result of the first query. It is not garbage 
> collected, so it continues to exist inside SQLAlchemy's identity map, 
> and it has the "raiseload" behaviour. When you run the second query, 
> SQLAlchemy notices that the session *already contains* the instance 
> that you queried for, so it returns that instance. It still has the 
> raiseload behaviour, so you get an exception when you access the "bs" 
> property. 
>
> So what you are really asking is "should relationship-loading 
> behaviour be stripped from instances already in the session when they 
> are returned from a query which did not specify those options?". I 
> suspect that the answer is no, but I don't know if it is actually 
> specified anywhere. 
>
> Does that make sense? 
>
> Simon 
>
> On Mon, Oct 15, 2018 at 1:49 PM Bartosz Stalewski 
> <[email protected] <javascript:>> wrote: 
> > 
> > Hi, 
> > 
> > I observed some strange (for me) behavior related to setting query 
> options. I am not sure if it works as intended or it is a bug. 
> > It seems to me that options are applied to query in a strange manner. 
> The posted below the code that show this behavior: 
> > 1) in both tests I am configuring sqlalchemy to raise an exception when 
> A.bs relation is accessed 
> > 2) but in test number 1, I am not assigning result of running query 
> (i.e. I am not reading it as I understand, since it is lazy) and exception 
> is not raised. 
> > 3) on the other hand in test number 2, I am assigning this result to 
> variable 'x' and an exception is raised (this is the only difference 
> between tests). 
> > 4) It does not matter if I run test_1 prior to test_2. 
> > 5) I tested it on current (1.2.12) version of sqlalchemy. 
> > 
> > Documentation (
> https://docs.sqlalchemy.org/en/latest/orm/loading_relationships.html#controlling-loading-via-options)
>  
> suggests that setting this option should be possible in 
> > the way I am doing it in test 1, but I think that my case shows that it 
> does not. 
> > 
> > Does it work as it is supposed to work and I am missing something or is 
> it a bug? 
> > 
> > Creating and populating tables: 
> > 
> > from sqlalchemy import Column, Integer, String, orm, ForeignKey, 
> create_engine 
> > from sqlalchemy.orm import relationship, Session 
> > from sqlalchemy.ext.declarative import declarative_base 
> > 
> > Base = declarative_base() 
> > 
> > 
> > class A(Base): 
> >     __tablename__ = 'a' 
> >     id = Column(Integer, primary_key=True) 
> >     name = Column(String) 
> > 
> >     def __repr__(self): return '<A id: {}, name: {}>'.format(self.id, 
> self.name) 
> > 
> > 
> > class B(Base): 
> >     __tablename__ = 'b' 
> >     id = Column(Integer, primary_key=True) 
> > 
> >     a_id = Column(Integer, ForeignKey('a.id'), index=True) 
> >     a = relationship('A', backref='bs') 
> > 
> >     def __repr__(self): return '<B id: {}, a_id: {}>'.format(self.id, 
> self.a_id) 
> > 
> > 
> > e = create_engine("sqlite://", echo=True) 
> > Base.metadata.create_all(e) 
> > 
> > s = Session(e) 
> > s.add(A(id=1, name='A1', bs=[B()])) 
> > s.add(A(id=2, name='A2', bs=[B(), B()])) 
> > s.commit() 
> > 
> > 
> > 
> > Tests definition: 
> > 
> > def test_1(): 
> >     # This DOES NOT affect further queries 
> >     print('------------------------ Test 1 ------------------------') 
> >     s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all() 
> >     print(s.query(A).filter_by(id=1).all()[0].bs) 
> > 
> > 
> > def test_2(): 
> >     # This DOES affect further queries 
> >     print('------------------------ Test 2 ------------------------') 
> >     x = s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all() 
> >     print(s.query(A).filter_by(id=1).all()[0].bs) 
> > 
> > 
> > test_1() 
> > test_2() 
> > 
> > 
> > test_1 does not raise any exception, while test_2 raises: 
> > 
> > 
> --------------------------------------------------------------------------- 
> > InvalidRequestError                       Traceback (most recent call 
> last) 
> > <ipython-input-2-6aad37f5c088> in <module> 
> >      24 create_data() 
> >      25 test_1() 
> > ---> 26 test_2() 
> > 
> > <ipython-input-2-6aad37f5c088> in test_2() 
> >      19     print('------------------------ Test 2 
> ------------------------') 
> >      20     x = 
> s.query(A).options(orm.raiseload(A.bs)).filter_by(id=1).all() 
> > ---> 21     print(s.query(A).filter_by(id=1).all()[0].bs) 
> >      22 
> >      23 
> > 
> > ~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py 
> in __get__(self, instance, owner) 
> >     240             return dict_[self.key] 
> >     241         else: 
> > --> 242             return self.impl.get(instance_state(instance), 
> dict_) 
> >     243 
> >     244 
> > 
> > ~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/attributes.py 
> in get(self, state, dict_, passive) 
> >     597                 elif key in state.callables: 
> >     598                     callable_ = state.callables[key] 
> > --> 599                     value = callable_(state, passive) 
> >     600                 elif self.callable_: 
> >     601                     value = self.callable_(state, passive) 
> > 
> > ~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py 
> in __call__(self, state, passive) 
> >     832         strategy = prop._strategies[self.strategy_key] 
> >     833 
> > --> 834         return strategy._load_for_state(state, passive) 
> >     835 
> >     836 
> > 
> > ~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py 
> in _load_for_state(self, state, passive) 
> >     587 
> >     588         if self._raise_always: 
> > --> 589             self._invoke_raise_load(state, passive, "raise") 
> >     590 
> >     591         session = _state_session(state) 
> > 
> > ~/Envs/importer/lib/python3.6/site-packages/sqlalchemy/orm/strategies.py 
> in _invoke_raise_load(self, state, passive, lazy) 
> >     562     def _invoke_raise_load(self, state, passive, lazy): 
> >     563         raise sa_exc.InvalidRequestError( 
> > --> 564             "'%s' is not available due to lazy='%s'" % (self, 
> lazy) 
> >     565         ) 
> >     566 
> > 
> > InvalidRequestError: 'A.bs' is not available due to lazy='raise' 
> > 
> > 
> > -- 
> > 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 [email protected] <javascript:>. 
> > To post to this group, send email to [email protected] 
> <javascript:>. 
> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> > For more options, visit https://groups.google.com/d/optout. 
>

-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to