Following up on this. I have implemented it in my application and it works 
beautifully when querying for the object.

However, while writing tests, I discovered that if the object is expired, 
it doesn't know how to refresh it. To explain the issue, I need to expand 
my original (simplified) example. The MyObjI18N class doesn't store the 
locale directly. Instead it has another foreignkey to a Language table. So 
my query in the above case looks actually like this:

and_(MyObj.id == MyObjI18N.obj_id, request.language_id == Language.id)

Now the problem is this: It doesn't seem to remember this language_id when 
refreshing, leading to the following exception:

.../python3.5/site-packages/sqlalchemy/orm/attributes.py:237: in __get__
    return self.impl.get(instance_state(instance), dict_)
.../python3.5/site-packages/sqlalchemy/orm/attributes.py:584: in get
    value = self.callable_(state, passive)
.../python3.5/site-packages/sqlalchemy/orm/strategies.py:553: in 
_load_for_state
    passive
.../python3.5/site-packages/sqlalchemy/orm/strategies.py:589: in 
_get_ident_for_use_get
    for pk in self.mapper.primary_key
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
_

.0 = <tuple_iterator object at 0x7fe545dc97b8>

    get_attr(
        state,
        dict_,
        self._equated_columns[pk],
        passive=passive)
>   for pk in self.mapper.primary_key
            ]
E           KeyError: Column('language_id', Integer(), 
ForeignKey('language.id'), table=<challenge_i18n>, primary_key=True, 
nullable=False)

.../python3.5/site-packages/sqlalchemy/orm/strategies.py:589: KeyError

I dug into the problem a bit but this goes way more into the core of 
SQLAlchemy than I am able to understand. In the end it seemed to be that on 
the join condition the lazy clause created didn't contain the equated 
column for language_id. But here my understanding of the working internals 
comes to an end.

I would have assumed that the instance somehow 'remembered' that column 
from when it was loaded and would refresh it in the same way as it was 
loaded. And from the setup, I feel like it should be possible. My best 
guess would be that the primaryjoin I return doesn't help it 'understand' 
that it has that link to a language_id column.

FWIW I am running SQLAlchemy 1.1.0b3, in case this is actually unexpected 
behaviour.

Cheers,
Florian

On Friday, 5 August 2016 00:24:30 UTC+10, Mike Bayer wrote:
>
>
>
> On 08/04/2016 10:14 AM, Florian Rüchel wrote: 
> > I have a relationship that depends on a query time variable to determine 
> > the correct join. The use case is request-time localization in a web 
> > application. When running the query during a request, I want to 
> > determine the locale and only load the translation for the current 
> > language for a given object. However, the primaryjoin condition callable 
> > is evaluated at mapping time instead which only happens once instead of 
> > on every request. 
> > 
> > Here is a quick sample: 
> > 
> > def get_myobj_primaryjoin(): 
> >     return and_(MyObj.id == MyObjI18N.obj_id, request.locale == 
> > MyObjI18N.lang) 
> > 
> > 
> > class MyObj(Base): 
> >     id = Column(Integer, primary_key=True) 
> >     _current_translation = relationship(MyObjI18N, uselist=False, 
> > primaryjoin=get_myobj_primaryjoin, lazy='joined') 
> > 
> > 
> > class MyObjI18N(Base): 
> >     obj_id = Column(ForeignKey(MyObj.id), primary_key=True) 
> >     lang = Column(String) 
> > 
> > This should give a rough idea of the issue: request.locale changes at 
> > query time, that is, if I do MyObj.query in two different requests, it 
> > won't work, it will always take the first time it was called. 
> > 
> > Note that I was previously using a with_transformation approach when 
> > building the query but I wanted to remove the necessity to add that 
> > every time a build a query and would have it much rather built 
> implicitly. 
> > 
> > Any ideas are highly appreciated, no argument I can pass to 
> > "relationship" seems to help my use case. 
>
>
> we use a bound parameter for this and a recipe for getting a value in 
> there can be seen at 
> https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/GlobalFilter . 
>     In particular the lazyload case can only be affected using a custom 
> MapperOption as described near the bottom of that recipe. 
>
>
>
> > 
> > -- 
> > 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 <javascript:> 
> > <mailto:sqlalchemy+unsubscr...@googlegroups.com <javascript:>>. 
> > To post to this group, send email to sqlal...@googlegroups.com 
> <javascript:> 
> > <mailto:sqlal...@googlegroups.com <javascript:>>. 
> > Visit this group at https://groups.google.com/group/sqlalchemy. 
> > For more options, visit https://groups.google.com/d/optout. 
>

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

Reply via email to