add "restrict_deletes=True" flag to relation()

Issue #1594 resolved
Former user created an issue

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:

  1. 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).
  2. 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)

  1. Mike Bayer 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

  2. Former user 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...

  3. Mike Bayer 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.

  4. Former user 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?

  5. Mike Bayer 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.

  6. Log in to comment