Well... If it was so simple, I'd have done it already. As I said, you
need to take into account tthe args and kwargs defined on the inverse
(and also prevent that inverse to setup the property too). I'll have a
look at the test thing tomorrow.
On 6/25/07, remi jolin <[EMAIL PROTECTED]> wrote:
>
> le 25.06.2007 17:15 Gaetan de Menten a écrit:
> > On 6/25/07, remi jolin <[EMAIL PROTECTED]> wrote:
> >
> >> le 23.06.2007 00:00 Gaetan de Menten a écrit:
> >>
> >>> This is a (known) bug in Elixir. The cause is that we don't setup
> >>> backrefs as we should.
> >>>
> >>> As I said to André Felipe Dias:
> >>> ======
> >>> Feel free to work on a patch, though I'm not sure how hard it would
> >>> be. Basically, when a relationship has an inverse, it must setup a
> >>> backref. The catch is that you must catch all the arguments of the
> >>> inverse relationship and pass them through to the backref.
> >>> ======
> >>>
> >>>
> >> Gaetan,
> >>
> >> I made a (simple) patch and a test for backrefs. It seems to work (at
> >> least as I expect it to work ;-) )
> >>
> >
> > Great news!
> >
> >
> >> I also found an issue in the test_multi.py test but I think it is a bug
> >> in the test (I've corrected it also).
> >>
> >
> > I'll see about that.
> >
> >
> >> The only test that does not pass is test_has_property but I think it
> >> because my version of sqlalchemy is too old (0.3.6) "ImportError: cannot
> >> import name column_property"
> >>
> >
> > Indeed.
> >
> >
> >> How can we get further ?
> >>
> >
> > Please send the patch here and I'll have a look at it and commit it if
> > it's good enough and otherwise tell you what's wrong.
> >
> >
> Here are all the patchs and the new test.
> As you see, the patch is very simple but seems to do the work...
>
> Index: elixir/relationships.py
> ===================================================================
> --- elixir/relationships.py (révision 135)
> +++ elixir/relationships.py (copie de travail)
> @@ -329,6 +329,8 @@
> (self.inverse_name == other.name or not
> self.inverse_name) and \ (other.inverse_name == self.name
> or not other.inverse_name)
>
> + def __repr__(self):
> + return "<%s name:%s>" % (self.__class__.__name__, self.name)
>
> class BelongsTo(Relationship):
> '''
> @@ -447,7 +449,10 @@
> if self.primaryjoin_clauses:
> kwargs['primaryjoin'] = and_(*self.primaryjoin_clauses)
> kwargs['uselist'] = False
> -
> +
> + if self.inverse:
> + kwargs['backref'] = self.inverse.name
> +
> self.property = relation(self.target, **kwargs)
> self.entity.mapper.add_property(self.name, self.property)
>
> @@ -487,6 +492,7 @@
> kwargs['primaryjoin'] = and_(*self.inverse.primaryjoin_clauses)
>
> kwargs['uselist'] = self.uselist
> + kwargs['backref'] = self.inverse.name
>
> self.property = relation(self.target, **kwargs)
> self.entity.mapper.add_property(self.name, self.property)
> @@ -660,6 +666,9 @@
> kwargs['order_by'] = \
>
> self.target._descriptor.translate_order_by(kwargs['order_by'])
>
> + if self.inverse:
> + kwargs['backref'] = self.inverse.name
> +
> self.property = relation(self.target,
> secondary=self.secondary_table,
> uselist=True, **kwargs)
> self.entity.mapper.add_property(self.name, self.property)
>
> -------------------------------
> Index: tests/test_multi.py
> ===================================================================
> --- tests/test_multi.py (révision 135)
> +++ tests/test_multi.py (copie de travail)
> @@ -52,7 +52,8 @@
>
> homer = Person.get_by(name="Homer")
> lisa = Person.get_by(name="Lisa")
> -
> + slh = Animal.get_by(name="Santa's Little Helper")
> +
> print homer
>
> assert len(homer.animals) == 2
> -----------------------
> The problem here is that after the objectstore.clear(), slh contained
> some "zombi" datas, not something from the database... Perharps, we
> should separate in 2 different functions the load of the database (up to
> objectstore.clear() and the requests so we get sure that a var doesn't
> keep an unrelevant data...
> Same issue with test_autoload.py.
>
> Index: tests/test_autoload.py
> ===================================================================
> --- tests/test_autoload.py (révision 135)
> +++ tests/test_autoload.py (copie de travail)
> @@ -101,7 +101,8 @@
>
> homer = Person.get_by(name="Homer")
> lisa = Person.get_by(name="Lisa")
> -
> + slh = Animal.get_by(name="Santa's Little Helper")
> +
> print homer
>
> assert len(homer.animals) == 2
> ------------------------------------
> tests/test_backref.py (new test...)
>
> """
> simple test case for backrefs
> """
>
> import sqlalchemy
> from elixir import *
>
> #-----------
>
> class TestMultiBelongsTo(object):
> def setup(self):
> global Person, Animal
>
> #---------------------------------------
> # classes for the multi belongs_to test
>
> class Person(Entity):
> has_field('name', Unicode(32))
>
> has_many('pets', of_kind='Animal', inverse='owner')
> has_many('animals', of_kind='Animal', inverse='feeder')
>
> def __str__(self):
> s = '%s\n' % self.name.encode('utf-8')
> for pet in self.pets:
> s += ' * pet: %s\n' % pet.name
> return s
>
> class Animal(Entity):
> has_field('name', String(15))
> has_field('color', String(15))
>
> belongs_to('owner', of_kind='Person')
> belongs_to('feeder', of_kind='Person')
>
> engine = sqlalchemy.create_engine('sqlite:///')
> metadata.connect(engine)
> create_all()
>
> def teardown(self):
> cleanup_all()
> objectstore.clear()
>
> def test_belongs_to_multi_ref(self):
> snowball = Animal(name="Snowball II", color="grey")
> slh = Animal(name="Santa's Little Helper")
> homer = Person(name="Homer", animals=[snowball, slh], pets=[slh])
> lisa = Person(name="Lisa", pets=[snowball])
>
> print homer
>
> assert lisa == snowball.owner
> assert homer == slh.feeder
> assert homer == lisa.pets[0].feeder
> assert homer == slh.owner
>
> objectstore.flush()
> objectstore.clear()
>
> homer = Person.get_by(name="Homer")
> lisa = Person.get_by(name="Lisa")
> slh = Animal.get_by(name="Santa's Little Helper")
>
> print "homer:", homer
> print "slh.owner:", slh.owner
>
> assert len(homer.animals) == 2
> assert homer == lisa.pets[0].feeder
> assert homer == slh.owner
>
> class TestMovies(object):
> def setup(self):
> global Director, Movie, Actor, Media
>
> class Director(Entity):
> with_fields(
> name = Field(Unicode(60))
> )
>
> has_many('movies', of_kind='Movie', inverse='director')
>
>
> class Movie(Entity):
> """
> simple movie class
> """
>
> # columns
> with_fields(
> title = Field(Unicode(50)),
> year = Field(Integer)
> )
>
> # relationships
> belongs_to('director', of_kind="Director", inverse='movies')
>
> has_and_belongs_to_many('actors', of_kind="Actor",
> inverse='movies') has_one('media', of_kind='Media',
> inverse='movie')
>
>
> class Actor(Entity):
> with_fields(
> name = Field(Unicode(60))
> )
>
> has_and_belongs_to_many('movies', of_kind="Movie",
> inverse="actors")
>
> class Media(Entity):
> with_fields(
> number = Field(Integer, primary_key=True)
> )
>
> belongs_to('movie', of_kind='Movie', inverse='media')
>
> engine = sqlalchemy.create_engine('sqlite:///')
> metadata.connect(engine)
> create_all()
>
> def teardown(self):
> drop_all()
> objectstore.clear()
>
> def test_bidirectional(self):
> brunner = Movie(title="Blade Runner", year=1982)
> alien = Movie(title="Alien", year=1979)
> swars = Movie(title="Star Wars", year=1977)
>
> m1 = Media(number=1)
> brunner.media = m1
> m7 = Media(number=7)
> m7.movie = alien
>
> rscott = Director(name="Ridley Scott")
> glucas = Director(name="George Lucas")
>
> hford = Actor(name="Harrison Ford")
> mhamill = Actor(name="Mark Hamill")
> sweaver = Actor(name="Sigourney Weaver")
>
> rscott.movies.append(brunner)
> rscott.movies.append(alien)
> swars.director = glucas
>
> swars.actors.append(hford)
> swars.actors.append(mhamill)
> alien.actors.append(sweaver)
> brunner.actors.append(hford)
>
> # directors
> assert rscott == brunner.director
> assert rscott == alien.director
> assert swars in glucas.movies
>
> # actors
> assert swars in hford.movies
> assert swars in mhamill.movies
> assert alien in sweaver.movies
> assert brunner in hford.movies
> assert len(hford.movies) == 2
>
> # media
> assert alien.media == m7
> assert m1.movie == brunner
>
>
> if __name__ == '__main__':
> test = TestMultiBelongsTo()
> test.setup()
> test.test_belongs_to_multi_ref()
> test.teardown()
>
> test = TestMovies()
> test.setup()
> test.test_bidirectional()
> test.teardown()
>
>
> >
>
--
Gaëtan de Menten
http://openhex.org
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"SQLElixir" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlelixir?hl=en
-~----------~----~----~----~------~----~------~--~---