1
0
mirror of https://github.com/django/django.git synced 2025-10-26 23:26:08 +00:00

Fixed #21961 -- Added support for database-level delete options for ForeignKey.

Thanks Simon Charette for pair programming.

Co-authored-by: Nick Stefan <NickStefan12@gmail.com>
Co-authored-by: Akash Kumar Sen <71623442+Akash-Kumar-Sen@users.noreply.github.com>
Co-authored-by: Simon Charette <charette.s@gmail.com>
This commit is contained in:
Mariusz Felisiak
2025-10-18 15:03:50 +02:00
committed by GitHub
parent b1e0262c9f
commit 0c487aa3a7
33 changed files with 838 additions and 67 deletions

View File

@@ -34,11 +34,16 @@ from .models import (
RChild,
RChildChild,
Referrer,
RelatedDbOption,
RelatedDbOptionGrandParent,
RelatedDbOptionParent,
RProxy,
S,
SetDefaultDbModel,
T,
User,
create_a,
create_related_db_option,
get_default_r,
)
@@ -76,18 +81,48 @@ class OnDeleteTests(TestCase):
a = A.objects.get(pk=a.pk)
self.assertIsNone(a.setnull)
def test_db_setnull(self):
a = create_related_db_option("db_setnull")
a.db_setnull.delete()
a = RelatedDbOption.objects.get(pk=a.pk)
self.assertIsNone(a.db_setnull)
def test_setdefault(self):
a = create_a("setdefault")
a.setdefault.delete()
a = A.objects.get(pk=a.pk)
self.assertEqual(self.DEFAULT, a.setdefault.pk)
@skipUnlessDBFeature("supports_on_delete_db_default")
def test_db_setdefault(self):
# Object cannot be created on the module initialization, use hardcoded
# PKs instead.
r = RelatedDbOptionParent.objects.create(pk=2)
default_r = RelatedDbOptionParent.objects.create(pk=1)
set_default_db_obj = SetDefaultDbModel.objects.create(db_setdefault=r)
set_default_db_obj.db_setdefault.delete()
set_default_db_obj = SetDefaultDbModel.objects.get(pk=set_default_db_obj.pk)
self.assertEqual(set_default_db_obj.db_setdefault, default_r)
def test_setdefault_none(self):
a = create_a("setdefault_none")
a.setdefault_none.delete()
a = A.objects.get(pk=a.pk)
self.assertIsNone(a.setdefault_none)
@skipUnlessDBFeature("supports_on_delete_db_default")
def test_db_setdefault_none(self):
# Object cannot be created on the module initialization, use hardcoded
# PKs instead.
r = RelatedDbOptionParent.objects.create(pk=2)
default_r = RelatedDbOptionParent.objects.create(pk=1)
set_default_db_obj = SetDefaultDbModel.objects.create(
db_setdefault_none=r, db_setdefault=default_r
)
set_default_db_obj.db_setdefault_none.delete()
set_default_db_obj = SetDefaultDbModel.objects.get(pk=set_default_db_obj.pk)
self.assertIsNone(set_default_db_obj.db_setdefault_none)
def test_cascade(self):
a = create_a("cascade")
a.cascade.delete()
@@ -359,6 +394,22 @@ class DeletionTests(TestCase):
self.assertNumQueries(5, s.delete)
self.assertFalse(S.objects.exists())
def test_db_cascade(self):
related_db_op = RelatedDbOptionParent.objects.create(
p=RelatedDbOptionGrandParent.objects.create()
)
RelatedDbOption.objects.bulk_create(
[
RelatedDbOption(db_cascade=related_db_op)
for _ in range(2 * GET_ITERATOR_CHUNK_SIZE)
]
)
with self.assertNumQueries(1):
results = related_db_op.delete()
self.assertEqual(results, (1, {"delete.RelatedDbOptionParent": 1}))
self.assertFalse(RelatedDbOption.objects.exists())
self.assertFalse(RelatedDbOptionParent.objects.exists())
def test_instance_update(self):
deleted = []
related_setnull_sets = []