#27272: Protected objects not deleted even if they would have been deleted via
cascade anyway
-------------------------------------+-------------------------------------
     Reporter:  Daniel Izquierdo     |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  1.10
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Daniel Izquierdo):

 @Simon it may be that this cannot be changed in Django without breaking
 backwards compatibility, but there's an argument to be made for the other
 proposed behavior: given multiple cascade paths, depending on which one we
 take first, the object preventing deletion of the referenced row may be
 not even exist anymore before the protected path is visited.

 Regarding `ON DELETE RESTRICT`, checked on Postgres 9.5 and it does delete
 the row:

 {{{
 #!sql
 psql (9.5.4)
 Type "help" for help.

 deltest=> CREATE TABLE artist ( id integer PRIMARY KEY, name text );
 CREATE TABLE
 deltest=> CREATE TABLE album ( id integer PRIMARY KEY, artist_id integer
 REFERENCES artist ON DELETE CASCADE);
 CREATE TABLE
 deltest=> CREATE TABLE song ( id integer PRIMARY KEY, artist_id integer
 REFERENCES artist ON DELETE CASCADE, album_id integer REFERENCES album ON
 DELETE RESTRICT);
 CREATE TABLE
 deltest=>
 deltest=> INSERT INTO artist VALUES (1, 'test');
 INSERT 0 1
 deltest=> INSERT INTO album (id, artist_id) VALUES (2, 1);
 INSERT 0 1
 deltest=> INSERT INTO song (id, artist_id, album_id) VALUES (3, 1, 2);
 INSERT 0 1
 deltest=>
 deltest=> -- This will fail
 deltest=> DELETE FROM album WHERE id = 2;
 ERROR:  update or delete on table "album" violates foreign key constraint
 "song_album_id_fkey" on table "song"
 DETAIL:  Key (id)=(2) is still referenced from table "song".
 deltest=>
 deltest=> -- This will succeed
 deltest=> DELETE FROM artist WHERE id = 1;
 DELETE 1
 deltest=>
 deltest=> -- Check it cascaded
 deltest=> SELECT * FROM song;
  id | artist_id | album_id
 ----+-----------+----------
 (0 rows)

 deltest=> SELECT * FROM album;
  id | artist_id
 ----+-----------
 (0 rows)
 deltest=>
 }}}

 Note that trying to delete the album directly fails as expected, but
 deleting the artist deletes everything because the song is reachable from
 the artist and supposed to cascade. I would argue the intention of the
 user doing this query (or doing `artist.delete()`) is to delete
 everything.

 @Tim I've attached a sample patch that makes the following tests pass.

 {{{
 #!python
 class TestDeletion(TestCase):
     def test_delete(self):
         artist = Artist.objects.create(name='test')
         album = Album.objects.create(artist=artist)
         Song.objects.create(artist=artist, album=album)

         with self.assertRaises(ProtectedError):
             album.delete()

         artist.delete()

     def test_delete_no_cascade(self):
         artist = Artist.objects.create(name='test')
         another_artist = Artist.objects.create(name='another test')
         album = Album.objects.create(artist=artist)
         Song.objects.create(artist=another_artist, album=album)

         with self.assertRaises(ProtectedError):
             album.delete()

         with self.assertRaises(ProtectedError):
             artist.delete()
 }}}

--
Ticket URL: <https://code.djangoproject.com/ticket/27272#comment:3>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.aba8c9ead8eec5a95320d8b5a41c7746%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to