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 [email protected] <javascript:>
> > <mailto:[email protected] <javascript:>>.
> > To post to this group, send email to [email protected]
> <javascript:>
> > <mailto:[email protected] <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 [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.