#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.