this time, I don't have a problem to solve - in fact I'm puzzled why there is none ;-)
I like to build a graph:
----------------------------------------------------------------------------------
class Node(Entity):
name = Field(Unicode(200), required=True)
parents = ManyToMany('Node')
children = ManyToMany('Node')
using_options(tablename='nodes')
def __repr__(self):
return self.name
----------------------------------------------------------------------------------
And it just works... :-o
When I declare nodes as children of a given node, I can retrieve the original node by
examining parents on the children...
Now, I like to know if someone sees a problem with the code above. Will it break in
some situations? (Would be handy to know it before I built it into my application...)
How does Elixir figure out the inverse relationships? Does anyone know if this code
is non-portable between databases?
Thank you very much :-)
fs
It might break if you inverse the fields order after creating the
table. This is a problem with Elixir in that the order you declare
fields in a bidirectional ManyToMany self-referential relationship is
significant. If you could add a ticket for this in the trac, that'd be
nice, so that I don't forget to fix that eventually.
> How does Elixir figure out the inverse relationships?
This is actually something I planned to document but never took the
time to. It looks for a matching relationship on the target entity. A
ManyToOne match as inverse of a OneToMany and vice versa, and a
ManyToMany match as inverse as a ManyToMany. It also pays attention
whether you specified an explicit inverse, and checks that each
relationship has only one inverse (if it finds more than one, it
raises an exception).
class Node(Entity):
name = Field(Unicode(200), required=True)
parents = ManyToMany('Node', inverse='children')
children = ManyToMany('Node', inverse='parents')
using_options(tablename='nodes')
> Does anyone know if this code
> is non-portable between databases?
Should be fine. The only problem that I know of is that the generated
many_to_many tables tend to have *very* long names and some database
do not accept such long names. But if you specify the tablename
manually you won't run into that problem:
class Node(Entity):
...
parents = ManyToMany('Node', tablename='node_children')
children = ManyToMany('Node', tablename='node_children')
using_options(tablename='nodes')
In that case, please specify the table name on both side of the
relationship (I think I remember it breaks otherwise, but I'd have to
look at the code to be sure).
--
Gaëtan de Menten
http://openhex.org
[x] done, http://elixir.ematia.de/trac/ticket/19
> class Node(Entity):
> name = Field(Unicode(200), required=True)
> parents = ManyToMany('Node', inverse='children')
> children = ManyToMany('Node', inverse='parents')
> using_options(tablename='nodes')
Ah! Now I see that the inverse statement came from SQLAlchemy which is why I
did not find out when looking at the docs...
Thank you very much for your detailed explanations - first class support :-))
fs
> Gaetan de Menten wrote:
> > It might break if you inverse the fields order after creating the
> > table. This is a problem with Elixir in that the order you declare
> > fields in a bidirectional ManyToMany self-referential relationship is
> > significant. If you could add a ticket for this in the trac, that'd be
> > nice, so that I don't forget to fix that eventually.
>
> [x] done, http://elixir.ematia.de/trac/ticket/19
Thanks. Note that contrary to what you put in the ticket, the problem
will be present whether the "inverse" keyword is missing or not.
> > class Node(Entity):
> > name = Field(Unicode(200), required=True)
> > parents = ManyToMany('Node', inverse='children')
> > children = ManyToMany('Node', inverse='parents')
> > using_options(tablename='nodes')
>
> Ah! Now I see that the inverse statement came from SQLAlchemy which is why I
> did not find out when looking at the docs...
Hmmm no. :) The backref argument come from SQLAlchemy, but this is not
the same. The inverse argument is Elixir specific, and is documented
(though not very prominently):
http://elixir.ematia.de/apidocs/elixir.relationships.html. We should
probably add a reference to that in the tutorial, I guess.
> Thank you very much for your detailed explanations - first class support :-))
Your welcome.
I think it needs to be documented in the list of arguments for every relationship on
http://elixir.ematia.de/apidocs/elixir.relationships.html.
e.g.:
"In addition to keyword arguments inherited from SQLAlchemy, ManyToMany
relationships accept the following optional (keyword) arguments:"
...
(lists "tablename", "remote_side", "local_side" and "order_by" but not inverse")
fs
I usually don't like to duplicate stuff, but I guess you're right.
Would you care to make a patch?