Re: [Sqlalchemy-tickets] [sqlalchemy] #2876: Using relationship with primaryjoin in declared_attr f
Brought to you by:
zzzeek
|
From: sqlalchemy <mi...@zz...> - 2013-11-27 16:05:04
|
#2876: Using relationship with primaryjoin in declared_attr fails
-----------------------------------+------------------------------------
Reporter: wichert | Owner: zzzeek
Type: defect | Status: closed
Priority: medium | Milestone:
Component: declarative | Severity: no triage selected yet
Resolution: worksforme | Keywords:
Progress State: completed/closed |
-----------------------------------+------------------------------------
Changes (by zzzeek):
* status: new => closed
* resolution: => worksforme
* status_field: awaiting triage => completed/closed
Comment:
TL;DR; - this situation is documented at
http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html
#mixing-in-relationships
relationship() definitions which require explicit primaryjoin,
order_by etc. expressions should use the string forms for these arguments,
so that they are evaluated as late as possible. To reference the mixin
class in these expressions, use the given cls to get its name:
The error message here is improved in 0.9, where you will get:
{{{
File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/sql/schema.py", line
1485, in _resolve_col_tokens
"this ForeignKey's parent column is not yet associated "
sqlalchemy.exc.InvalidRequestError: this ForeignKey's parent column is not
yet associated with a Table.
}}}
Your method avatar_original_id creates a new `Column` object *each time it
is called*. When you call it within your `avatar_original` method, you
get a `Column` back, but '''that Column object is unknown to any other
aspect of the program'''.
So the class gets mapped normally, declarative calls upon
`avatar_original_id` to get at the `Column` that will actually be mapped,
and the one you've put in your `relationship()` has no parent table.
The solution - except in the most simplistic cases, strings or lambdas
should always be used for relationship arguments in declarative:
{{{
#!python
@declared_attr
def avatar_original(cls):
return relationship(Image, cascade='all',
primaryjoin=lambda: (cls.avatar_original_id == Image.id))
}}}
or
{{{
#!python
@declared_attr
def avatar_original(cls):
return relationship(Image, cascade='all',
primaryjoin="%s.avatar_original_id == Image.id" %
cls.__name__)
}}}
the latter is documented in the last example at:
http://docs.sqlalchemy.org/en/rel_0_9/orm/extensions/declarative.html
#mixing-in-relationships
the "lambda:" form should probably be added to the docs as it is handy.
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2876#comment:1>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|