- attached refint.py
add "restrict_deletes=True" flag to relation()
Having a foreign key defined with {{{ondelete='RESTRICT'}}} has no effect when deleting parent object through ORM (ie. {{{session.delete}}}). This can be seen in two ways:
- When the foreign key column is NOT defined with {{{nullable=False}}} (ie. it is allowed to be nullable), delete works as if {{{ondelete='SET NULL'}}} was in effect (see attached test case).
- When the foreign key is not allowed to be null (ie. {{{nullable=True}}}), the actual error thrown upon deleting is ''null value in column <child_column> violates not-null constraint'', while it should be ''update or delete on table <parent_table> violates foreign key constraint''.
The effect is that deletes are actually not RESTRICTed, which is inconsistent with the expected behaviour, and different from deletes through {{{conn.execute(table.delete()))}}} or {{{SQL DELETE}}} (both of which throw an error under the same setup).
Attached is a self-contained test case for this.
Comments (9)
-
Account Deleted -
repo owner - changed milestone to 0.6.xx
set nullable=False on your foreign key for now
-
repo owner - changed title to add "restrict_deletes=True" flag to relation()
- marked as enhancement
-
repo owner - changed status to invalid
- removed milestone
whoops, forgot about "passive_deletes='all'".
mapper(Person, persons, properties={ 'country': relation(Country, backref=backref('persons', passive_deletes='all'), passive_updates=True)})
test passes
-
Account Deleted Damn, I've tried with passive_deletes='all', but it didn't occur to me that it needs to be in the backref. Shouldn't passive_updates then also be moved in the backref, ie:
'country': relation(Country, backref=backref('persons', passive_deletes='all', passive_updates=True))})
Also, the docs state: "Note that the foreign key attributes on in-session child objects will not be changed after a flush occurs so this is a very special use-case setting."
Does this mean that in-session objects wouldn't be deleted? My concern is that docs state that this is a very special use-case setting, and this usage dosen't seem all that special...
-
repo owner people have an issue like this once every 6 months, and nobody has ever asked specifically about "RESTRICT" before. hence until now it was "special". Since I never considered RESTRICT, we should add a note to the docstring here regarding it.
-
Account Deleted I see now that the second part of my previous question was stupid - in fact, we want no objects to be deleted so passive_deletes='all' is exactly what is needed. As I said, reading the docs it seemed like the right option but it didn't occur to me that in needs to be put in the backref.
Just the last detail - {{{passive_updates=True}}} should then also go in the backref, correct?
-
repo owner yes, a relation() is specified in terms of its parent mapped class, so any actions which occur as the result of events on that class are configured there. This is the opposite declaration style of a FOREIGN KEY, which is specified on the dependent table, even though the events described on it are in terms of the parent table.
-
Account Deleted OK, now it all makes sense. Thanks a lot Mike!
- Log in to comment
Self-contained test case