There's one problem : the error I'm getting is not on the foreign key constraint it's on the NOT NULL contraint.
Now there's a weired thing happening :
I define my models like this :
<code>
class BaseModel(Entity):
using_options(abstract=True)
repr_attr = "name"
def __repr__(self):
"""
"""
return "<%s '%s' id='%s'>" % (self.__class__.__name__,getattr(self,self.repr_attr,id(self)),self.id)
class Country(BaseModel):
"""
"""
using_options(tablename = "countries")
name = Field(Unicode,nullable=False)
cities = OneToMany("City")
class City(BaseModel):
"""
"""
using_options(tablename = "cities")
name = Field(Unicode)
country = ManyToOne("Country",ondelete="restrict")
</code>
The table definition that elixir generates is correct : my foreign key contraint is there :
<sql>
CREATE TABLE cities (
id SERIAL NOT NULL,
name VARCHAR,
country_id INTEGER,
PRIMARY KEY (id),
CONSTRAINT cities_country_id_fk FOREIGN KEY(country_id) REFERENCES countries (id) ON DELETE restrict
)
</sql>
Here's the rest of the script
<code>
metadata.bind = "postgres://coriolis:coriolis234access@localhost/testdb"
metadata.bind.echo = True
setup_all()
drop_all()
create_all()
session.commit()
# just to make them global
algeria = None
algiers = None
def create():
global algeria,algiers
algeria = Country(name=u"Algeria")
algiers = City(name=u"Algiers",country=algeria)
session.commit()
def delete():
global algeria,algiers
# THIS DOSEN'T BREAK which is NOT what we want
algeria.delete()
session.commit()
create()
#delete()
session.commit()
</code>
First, I comment the delete() function call to let the created instances there on the database. Then I go on phppgadmin and tries to delete the country but get an error (table cities still referencing etc.), which is the desired behaviour.
Now i re-run the script and uncomment the delete function call like this :
<code>
metadata.bind = "postgres://coriolis:coriolis234access@localhost/testdb"
metadata.bind.echo = True
setup_all()
drop_all()
create_all()
session.commit()
# just to make them global
algeria = None
algiers = None
def create():
global algeria,algiers
algeria = Country(name=u"Algeria")
algiers = City(name=u"Algiers",country=algeria)
session.commit()
def delete():
global algeria,algiers
# THIS DOSEN'T BREAK which is NOT what we want
algeria.delete()
session.commit()
create()
delete()
session.commit()
</code>
But the script dosen't raise the exception.
Now a solution proposed by Diez was to add a required=True on the country relation, which kind of works, but is semantically acceptable. Furthermore, on some of my models, certain relations are not required, so setting a required=True dosen't make sens I guess, but I still want them to prevent a deletion on the other side of the relation if they are still pointing to it.
What can I do to impement this ? shouldn't ondelete="restrict" be enough ?
Thank you for your precious help.
Y.Chaouche
> Hi list,
>
> There's one problem : the error I'm getting is not on the foreign
> key constraint it's on the NOT NULL contraint.
This is because SA issues an update to the city, setting the country
to NULL. You can see that if you'd use my code that set the bind's
echo property to True.
Now honestly I don't know how to fix this, but this might help:
http://www.sqlalchemy.org/docs/05/mappers.html#using-passive-deletes
Passing passive_deletes=True to the OneToMany-relation might solve the
issue of trying to update child-relations.
Diez
Should I consider this a bug and open a ticket for it ?
I'd say no. It is a documented behavior. Just not the one you expected.
Diez
passive_deletes="all" should do what you want (seems to be only
available in SA 0.6+). I have never used it myself and I must admit I
am quite astonished as to how hard it was (how deep in the docs I had
to dig) to find how to support this (IMO) trivial setup.
If that does not work for you, please ask on SQLAlchemy's mailing
list, or open a bug in their tracker, as this problem is not specific
to Elixir.
Hope it helps,
--
Gaëtan de Menten
> After lots of inverstigation,
>
> i found the "passive_deletes" option that was missing from the whole
> discussion, and curiously not needed on our SA models to raise the
> exception.
Missing from this discussion? It was the first answer of me in the re-
opened thread here, and already solved the issue for the OP two weeks
ago...
Diez