diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py index 92fe4affb9..3a462f1c4c 100644 --- a/django/db/models/deletion.py +++ b/django/db/models/deletion.py @@ -277,6 +277,7 @@ class Collector: if self.can_fast_delete(instance): with transaction.mark_for_rollback_on_error(): count = sql.DeleteQuery(model).delete_batch([instance.pk], self.using) + setattr(instance, model._meta.pk.attname, None) return count, {model._meta.label: count} with transaction.atomic(using=self.using, savepoint=False): diff --git a/docs/releases/2.2.1.txt b/docs/releases/2.2.1.txt index f7ac012fb7..2b82a33d29 100644 --- a/docs/releases/2.2.1.txt +++ b/docs/releases/2.2.1.txt @@ -22,3 +22,6 @@ Bugfixes :class:`~django.contrib.postgres.aggregates.ArrayAgg` and :class:`~django.contrib.postgres.aggregates.StringAgg` when it contains an expression with params (:ticket:`30332`). + +* Fixed a regression in Django 2.2 that caused a single instance fast-delete + to not set the primary key to ``None`` (:ticket:`30330`). diff --git a/tests/delete/tests.py b/tests/delete/tests.py index 55eeb226ea..ed47d0667d 100644 --- a/tests/delete/tests.py +++ b/tests/delete/tests.py @@ -1,6 +1,7 @@ from math import ceil from django.db import IntegrityError, connection, models +from django.db.models.deletion import Collector from django.db.models.sql.constants import GET_ITERATOR_CHUNK_SIZE from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature @@ -471,6 +472,14 @@ class FastDeleteTests(TestCase): self.assertEqual(User.objects.count(), 1) self.assertTrue(User.objects.filter(pk=u2.pk).exists()) + def test_fast_delete_instance_set_pk_none(self): + u = User.objects.create() + # User can be fast-deleted. + collector = Collector(using='default') + self.assertTrue(collector.can_fast_delete(u)) + u.delete() + self.assertIsNone(u.pk) + def test_fast_delete_joined_qs(self): a = Avatar.objects.create(desc='a') User.objects.create(avatar=a)