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 <[email protected]> wrote:
>
>> From: alex bodnaru <[email protected]>
>> Subject: Re: [elixir] problem with cascade deletes
>> To: [email protected]
>> 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 <[email protected]>
>> wrote:
>>>> From: alex bodnaru <[email protected]>
>>>> Subject: [elixir] problem with cascade deletes
>>>> To: [email protected]
>>>> 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 [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.
>>>>
>>>>
>>>
>>>
>> --
>> 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.
>>
>>
>
>
>
--
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.
"""
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