hey yacine, friends, indeed the problem came partly because i haven't followed the traces of elixir close enough: i've used backref instead of inverse for manytoone relations.
the only drawback of using inverse, is that it requires the inverse relation to really exist, hence it can't be implied. here comes to light an elixir extension i've made a time ago (inverse_orphans), that would create an inverse relation on the onetomany side when it is missing. for your interest, the plugin is attached. i'd extend this plugin to take kwargs too. best regards, alex On 09/12/2010 10:37 AM, chaouche yacine wrote: > Yes, except I wanted the children *not* to be deleted but raise an > integrity_error exception instead, because what was done is that they were > not deleted but their FK (pointing to the parent) were set to NULL and they > were raising a non-null constraint related exception. > > > > > --- On Sun, 9/12/10, alex bodnaru <alexbodn.gro...@gmail.com> wrote: > >> From: alex bodnaru <alexbodn.gro...@gmail.com> >> Subject: Re: [elixir] problem with cascade deletes >> To: sqleli...@googlegroups.com >> Date: Sunday, September 12, 2010, 1:21 AM >> hello yacine, >> >> elixir isn't known to reinvent sa, but please point me to >> things you would >> change for a pure approach. >> part of the lower level stuff is needed to turn foreign >> keys on in sqlite. >> >> in the mean time, i did a declarative example which fails >> like elixir. >> >> btw. this is the same problem you have also previously >> reported on this list. >> >> alex >> >> On 09/12/2010 09:58 AM, chaouche yacine wrote: >>> hello alex, >>> >>> In your elixir program, you are mixing some imports >> from sqlalchemy (create_engine from example) with imports >> from elixir. Did you try an elixir only approach ? >>> Y.Chaouche >>> >>> >>> >>> --- On Sat, 9/11/10, alex bodnaru <alexbodn.gro...@gmail.com> >> wrote: >>>> From: alex bodnaru <alexbodn.gro...@gmail.com> >>>> Subject: [elixir] problem with cascade deletes >>>> To: sqleli...@googlegroups.com >>>> Date: Saturday, September 11, 2010, 6:31 AM >>>> >>>> hello friends, >>>> >>>> there seems to be a flaw in elixir with cascade >> deletes. >>>> i have a program that does it with sqlalchemy orm, >> and a >>>> similar one to do it >>>> with elixir. >>>> instead of deleting the elixir program only nulls >> the keys >>>> in the child. >>>> >>>> the programs are attached. >>>> >>>> best regards, >>>> alex >>>> >>>> -- >>>> You received this message because you are >> subscribed to the >>>> Google Groups "SQLElixir" group. >>>> To post to this group, send email to sqleli...@googlegroups.com. >>>> To unsubscribe from this group, send email to >> sqlelixir+unsubscr...@googlegroups.com. >>>> For more options, visit this group at >>>> http://groups.google.com/group/sqlelixir?hl=en. >>>> >>>> >>> >>> >> -- >> You received this message because you are subscribed to the >> Google Groups "SQLElixir" group. >> To post to this group, send email to sqleli...@googlegroups.com. >> To unsubscribe from this group, send email to >> sqlelixir+unsubscr...@googlegroups.com. >> For more options, visit this group at >> http://groups.google.com/group/sqlelixir?hl=en. >> >> > > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.
""" inverse_orphans Elixir Statement Generator =============== inverse_orphans =============== i am using an identity model module from a third party, having, among others, an User class. this model file might well be upgraded by it's supplier. in another model file, which imports the identity model entities, i have a Person class, which has a ManyToOne relationship with the User table. However i'd like to also know the Person which references a given User, adding OneToMany relationships to User, will need to be maintained everytime the supplier upgrades identity model. to implement this, i am giving an inverse name on the ManyToOne side, and adding an after_mapper action to create the OneToMany relationship. """ from elixir.statements import Statement from elixir import OneToOne, OneToMany, ManyToOne, ManyToMany __all__ = ['inverse_orphans'] __doc_all__ = __all__ #TODO: inherit from entity builder class inverse_orphans_entity_builder(object): """An inverse_orphans Elixir Statement object""" def __init__(self, entity): self.entity = entity def before_table(self): ''' if we name an inverse relationship which is not already defined on the target, here we create the inverse relationship on the target. should run this for each relationship property. ''' for r in self.entity._descriptor.relationships: desc = r.target._descriptor if r.inverse_name and desc.find_relationship(r.inverse_name) is None: if type(r) == ManyToOne: # should probably test uselist if 'unique' in r.column_kwargs and r.column_kwargs['unique']: invclass = OneToOne else: invclass = OneToMany elif type(r) == ManyToMany: invclass = ManyToMany else: invclass = None else: invclass = None if invclass: invprop = invclass(r.entity.__name__, inverse=r.name) invprop._target = r.entity setattr(r.target, r.inverse_name, invprop) invprop.attach(r.target, r.inverse_name) inverse_orphans = Statement(inverse_orphans_entity_builder)
from elixir import * from elixir.ext.inverse_orphans import inverse_orphans metadata.bind = "sqlite:///:memory:" metadata.bind.echo = False class Movie(Entity): title = Field(Unicode(30)) year = Field(Integer) description = Field(Text) # director = ManyToOne('Director', inverse='movies') # main_genre = ManyToOne('Genre', inverse='movies_with_main') # inverse_orphans() director = ManyToOne('Director', backref='movies') main_genre = ManyToOne('Genre', backref='movies_with_main') def __repr__(self): return '<Movie "%s" (%d)>' % (self.title, self.year) class Director(Entity): name = Field(Unicode(60)) #movies = OneToMany('Movie', inverse='director') def __repr__(self): return '<Director "%s">' % self.name class Genre(Entity): name = Field(Unicode(15), primary_key=True) abbrev = Field(Unicode(15), primary_key=True) movies = ManyToMany('Movie', backref='genres') inverse_orphans() def __repr__(self): return '<Genre "%s">' % self.name setup_all(True) #create_all() scifi = Genre(name="Science-Fiction", abbrev='sf') western = Genre(name='Western', abbrev='we') rscott = Director(name="Ridley Scott") glucas = Director(name="George Lucas") alien = Movie(title="Alien", year=1979, director=rscott, genres=[scifi, Genre(name="Horror", abbrev='hr')], main_genre=scifi) swars = Movie(title="Star Wars", year=1977, director=glucas, genres=[scifi], main_genre=scifi) brunner = Movie(title="Blade Runner", year=1982, director=rscott, genres=[scifi], main_genre=western) #rscott.movies.append(brunner) #rscott.movies.append(alien) #swars.director = glucas print 'movies by rscott:', rscott.movies print 'movies by glucas:', glucas.movies print 'genres of alien:', alien.genres print 'movies with main_genre scifi:', scifi.movies_with_main print 'movies with main_genre western:', western.movies_with_main print 'movies of glucas:', glucas.movies