summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2025-10-18 15:03:50 +0200
committerGitHub <noreply@github.com>2025-10-18 15:03:50 +0200
commit0c487aa3a7b2417481bf48c1e5355c855873e210 (patch)
tree33b92a3bdf11f66d0f67fe4b4338084c7028c709 /tests
parentb1e0262c9f9d11eae6230b51c5aa5d71122d5f05 (diff)
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>
Diffstat (limited to 'tests')
-rw-r--r--tests/admin_utils/models.py10
-rw-r--r--tests/admin_utils/tests.py25
-rw-r--r--tests/contenttypes_tests/test_checks.py21
-rw-r--r--tests/delete/models.py49
-rw-r--r--tests/delete/tests.py51
-rw-r--r--tests/invalid_models_tests/test_models.py61
-rw-r--r--tests/invalid_models_tests/test_relative_fields.py198
-rw-r--r--tests/migrations/test_writer.py17
-rw-r--r--tests/schema/tests.py96
9 files changed, 523 insertions, 5 deletions
diff --git a/tests/admin_utils/models.py b/tests/admin_utils/models.py
index 243f314b03..e5d2b67887 100644
--- a/tests/admin_utils/models.py
+++ b/tests/admin_utils/models.py
@@ -40,7 +40,7 @@ class ArticleProxy(Article):
proxy = True
-class Count(models.Model):
+class Cascade(models.Model):
num = models.PositiveSmallIntegerField()
parent = models.ForeignKey("self", models.CASCADE, null=True)
@@ -48,6 +48,14 @@ class Count(models.Model):
return str(self.num)
+class DBCascade(models.Model):
+ num = models.PositiveSmallIntegerField()
+ parent = models.ForeignKey("self", models.DB_CASCADE, null=True)
+
+ def __str__(self):
+ return str(self.num)
+
+
class Event(models.Model):
date = models.DateTimeField(auto_now_add=True)
diff --git a/tests/admin_utils/tests.py b/tests/admin_utils/tests.py
index c90836c6d8..ce32535c52 100644
--- a/tests/admin_utils/tests.py
+++ b/tests/admin_utils/tests.py
@@ -26,7 +26,17 @@ from django.test.utils import isolate_apps
from django.utils.formats import localize
from django.utils.safestring import mark_safe
-from .models import Article, Car, Count, Event, EventGuide, Location, Site, Vehicle
+from .models import (
+ Article,
+ Car,
+ Cascade,
+ DBCascade,
+ Event,
+ EventGuide,
+ Location,
+ Site,
+ Vehicle,
+)
class NestedObjectsTests(TestCase):
@@ -34,10 +44,12 @@ class NestedObjectsTests(TestCase):
Tests for ``NestedObject`` utility collection.
"""
+ cascade_model = Cascade
+
@classmethod
def setUpTestData(cls):
cls.n = NestedObjects(using=DEFAULT_DB_ALIAS)
- cls.objs = [Count.objects.create(num=i) for i in range(5)]
+ cls.objs = [cls.cascade_model.objects.create(num=i) for i in range(5)]
def _check(self, target):
self.assertEqual(self.n.nested(lambda obj: obj.num), target)
@@ -103,6 +115,15 @@ class NestedObjectsTests(TestCase):
n.collect([Vehicle.objects.first()])
+class DBNestedObjectsTests(NestedObjectsTests):
+ """
+ Exercise NestedObjectsTests but with a model that makes use of DB_CASCADE
+ instead of CASCADE to ensure proper collection of objects takes place.
+ """
+
+ cascade_model = DBCascade
+
+
class UtilsTests(SimpleTestCase):
empty_value = "-empty-"
diff --git a/tests/contenttypes_tests/test_checks.py b/tests/contenttypes_tests/test_checks.py
index c33920f6b7..5c88b71777 100644
--- a/tests/contenttypes_tests/test_checks.py
+++ b/tests/contenttypes_tests/test_checks.py
@@ -80,6 +80,27 @@ class GenericForeignKeyTests(SimpleTestCase):
],
)
+ def test_content_type_db_on_delete(self):
+ class Model(models.Model):
+ content_type = models.ForeignKey(ContentType, models.DB_CASCADE)
+ object_id = models.PositiveIntegerField()
+ content_object = GenericForeignKey("content_type", "object_id")
+
+ field = Model._meta.get_field("content_object")
+
+ self.assertEqual(
+ field.check(),
+ [
+ checks.Error(
+ "'Model.content_type' cannot use the database-level on_delete "
+ "variant.",
+ hint="Change the on_delete rule to the non-database variant.",
+ obj=field,
+ id="contenttypes.E006",
+ )
+ ],
+ )
+
def test_missing_object_id_field(self):
class TaggedItem(models.Model):
content_type = models.ForeignKey(ContentType, models.CASCADE)
diff --git a/tests/delete/models.py b/tests/delete/models.py
index 7f123b3396..bd9caf42a7 100644
--- a/tests/delete/models.py
+++ b/tests/delete/models.py
@@ -41,6 +41,46 @@ class RChildChild(RChild):
pass
+class RelatedDbOptionGrandParent(models.Model):
+ pass
+
+
+class RelatedDbOptionParent(models.Model):
+ p = models.ForeignKey(RelatedDbOptionGrandParent, models.DB_CASCADE, null=True)
+
+
+class RelatedDbOption(models.Model):
+ name = models.CharField(max_length=30)
+ db_setnull = models.ForeignKey(
+ RelatedDbOptionParent,
+ models.DB_SET_NULL,
+ null=True,
+ related_name="db_setnull_set",
+ )
+ db_cascade = models.ForeignKey(
+ RelatedDbOptionParent, models.DB_CASCADE, related_name="db_cascade_set"
+ )
+
+
+class SetDefaultDbModel(models.Model):
+ db_setdefault = models.ForeignKey(
+ RelatedDbOptionParent,
+ models.DB_SET_DEFAULT,
+ db_default=models.Value(1),
+ related_name="db_setdefault_set",
+ )
+ db_setdefault_none = models.ForeignKey(
+ RelatedDbOptionParent,
+ models.DB_SET_DEFAULT,
+ db_default=None,
+ null=True,
+ related_name="db_setnull_nullable_set",
+ )
+
+ class Meta:
+ required_db_features = {"supports_on_delete_db_default"}
+
+
class A(models.Model):
name = models.CharField(max_length=30)
@@ -119,6 +159,15 @@ def create_a(name):
return a
+def create_related_db_option(name):
+ a = RelatedDbOption(name=name)
+ for name in ["db_setnull", "db_cascade"]:
+ r = RelatedDbOptionParent.objects.create()
+ setattr(a, name, r)
+ a.save()
+ return a
+
+
class M(models.Model):
m2m = models.ManyToManyField(R, related_name="m_set")
m2m_through = models.ManyToManyField(R, through="MR", related_name="m_through_set")
diff --git a/tests/delete/tests.py b/tests/delete/tests.py
index 59140b5c62..8d525d1e5f 100644
--- a/tests/delete/tests.py
+++ b/tests/delete/tests.py
@@ -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 = []
diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py
index 2a39e250bd..fe3c812615 100644
--- a/tests/invalid_models_tests/test_models.py
+++ b/tests/invalid_models_tests/test_models.py
@@ -3062,3 +3062,64 @@ class ConstraintsTests(TestCase):
),
],
)
+
+
+@isolate_apps("invalid_models_tests")
+class RelatedFieldTests(SimpleTestCase):
+ def test_on_delete_python_db_variants(self):
+ class Artist(models.Model):
+ pass
+
+ class Album(models.Model):
+ artist = models.ForeignKey(Artist, models.CASCADE)
+
+ class Song(models.Model):
+ album = models.ForeignKey(Album, models.RESTRICT)
+ artist = models.ForeignKey(Artist, models.DB_CASCADE)
+
+ self.assertEqual(
+ Song.check(databases=self.databases),
+ [
+ Error(
+ "The model cannot have related fields with both database-level and "
+ "Python-level on_delete variants.",
+ obj=Song,
+ id="models.E050",
+ ),
+ ],
+ )
+
+ def test_on_delete_python_db_variants_auto_created(self):
+ class SharedModel(models.Model):
+ pass
+
+ class Parent(models.Model):
+ pass
+
+ class Child(SharedModel):
+ parent = models.ForeignKey(Parent, on_delete=models.DB_CASCADE)
+
+ self.assertEqual(
+ Child.check(databases=self.databases),
+ [
+ Error(
+ "The model cannot have related fields with both database-level and "
+ "Python-level on_delete variants.",
+ obj=Child,
+ id="models.E050",
+ ),
+ ],
+ )
+
+ def test_on_delete_db_do_nothing(self):
+ class Artist(models.Model):
+ pass
+
+ class Album(models.Model):
+ artist = models.ForeignKey(Artist, models.CASCADE)
+
+ class Song(models.Model):
+ album = models.ForeignKey(Album, models.DO_NOTHING)
+ artist = models.ForeignKey(Artist, models.DB_CASCADE)
+
+ self.assertEqual(Song.check(databases=self.databases), [])
diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py
index ed6d39f7c6..e73f22ab41 100644
--- a/tests/invalid_models_tests/test_relative_fields.py
+++ b/tests/invalid_models_tests/test_relative_fields.py
@@ -3,7 +3,8 @@ from unittest import mock
from django.core.checks import Error
from django.core.checks import Warning as DjangoWarning
from django.db import connection, models
-from django.test.testcases import SimpleTestCase
+from django.test import skipUnlessDBFeature
+from django.test.testcases import SimpleTestCase, TestCase
from django.test.utils import isolate_apps, modify_settings, override_settings
@@ -751,6 +752,29 @@ class RelativeFieldTests(SimpleTestCase):
],
)
+ def test_on_delete_db_set_null_on_non_nullable_field(self):
+ class Person(models.Model):
+ pass
+
+ class Model(models.Model):
+ foreign_key = models.ForeignKey("Person", models.DB_SET_NULL)
+
+ field = Model._meta.get_field("foreign_key")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "Field specifies on_delete=DB_SET_NULL, but cannot be null.",
+ hint=(
+ "Set null=True argument on the field, or change the on_delete "
+ "rule."
+ ),
+ obj=field,
+ id="fields.E320",
+ ),
+ ],
+ )
+
def test_on_delete_set_default_without_default_value(self):
class Person(models.Model):
pass
@@ -2259,3 +2283,175 @@ class M2mThroughFieldsTests(SimpleTestCase):
),
],
)
+
+
+@isolate_apps("invalid_models_tests")
+class DatabaseLevelOnDeleteTests(TestCase):
+
+ def test_db_set_default_support(self):
+ class Parent(models.Model):
+ pass
+
+ class Child(models.Model):
+ parent = models.ForeignKey(
+ Parent, models.DB_SET_DEFAULT, db_default=models.Value(1)
+ )
+
+ field = Child._meta.get_field("parent")
+ expected = (
+ []
+ if connection.features.supports_on_delete_db_default
+ else [
+ Error(
+ f"{connection.display_name} does not support a DB_SET_DEFAULT.",
+ hint="Change the on_delete rule to SET_DEFAULT.",
+ obj=field,
+ id="fields.E324",
+ )
+ ]
+ )
+ self.assertEqual(field.check(databases=self.databases), expected)
+
+ def test_db_set_default_required_db_features(self):
+ class Parent(models.Model):
+ pass
+
+ class Child(models.Model):
+ parent = models.ForeignKey(
+ Parent, models.DB_SET_DEFAULT, db_default=models.Value(1)
+ )
+
+ class Meta:
+ required_db_features = {"supports_on_delete_db_default"}
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(field.check(databases=self.databases), [])
+
+ @skipUnlessDBFeature("supports_on_delete_db_default")
+ def test_db_set_default_no_db_default(self):
+ class Parent(models.Model):
+ pass
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, models.DB_SET_DEFAULT)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(databases=self.databases),
+ [
+ Error(
+ "Field specifies on_delete=DB_SET_DEFAULT, but has no db_default "
+ "value.",
+ hint="Set a db_default value, or change the on_delete rule.",
+ obj=field,
+ id="fields.E322",
+ )
+ ],
+ )
+
+ def test_python_db_chain(self):
+ class GrandParent(models.Model):
+ pass
+
+ class Parent(models.Model):
+ grand_parent = models.ForeignKey(GrandParent, models.DB_CASCADE)
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, models.RESTRICT)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(databases=self.databases),
+ [
+ Error(
+ "Field specifies Python-level on_delete variant, but referenced "
+ "model uses database-level variant.",
+ hint=(
+ "Use either database or Python on_delete variants uniformly in "
+ "the references chain."
+ ),
+ obj=field,
+ id="fields.E323",
+ )
+ ],
+ )
+
+ def test_db_python_chain(self):
+ class GrandParent(models.Model):
+ pass
+
+ class Parent(models.Model):
+ grand_parent = models.ForeignKey(GrandParent, models.CASCADE)
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, models.DB_SET_NULL, null=True)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(databases=self.databases),
+ [
+ Error(
+ "Field specifies database-level on_delete variant, but referenced "
+ "model uses Python-level variant.",
+ hint=(
+ "Use either database or Python on_delete variants uniformly in "
+ "the references chain."
+ ),
+ obj=field,
+ id="fields.E323",
+ )
+ ],
+ )
+
+ def test_db_python_chain_auto_created(self):
+ class GrandParent(models.Model):
+ pass
+
+ class Parent(GrandParent):
+ pass
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, on_delete=models.DB_CASCADE)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(databases=self.databases),
+ [
+ Error(
+ "Field specifies database-level on_delete variant, but referenced "
+ "model uses Python-level variant.",
+ hint=(
+ "Use either database or Python on_delete variants uniformly in "
+ "the references chain."
+ ),
+ obj=field,
+ id="fields.E323",
+ )
+ ],
+ )
+
+ def test_db_do_nothing_chain(self):
+ class GrandParent(models.Model):
+ pass
+
+ class Parent(models.Model):
+ grand_parent = models.ForeignKey(GrandParent, models.DO_NOTHING)
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, models.DB_SET_NULL, null=True)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(field.check(databases=self.databases), [])
+
+ def test_do_nothing_db_chain(self):
+ class GrandParent(models.Model):
+ pass
+
+ class Parent(models.Model):
+ grand_parent = models.ForeignKey(GrandParent, models.DB_SET_NULL, null=True)
+
+ class Child(models.Model):
+ parent = models.ForeignKey(Parent, models.DO_NOTHING)
+
+ field = Child._meta.get_field("parent")
+ self.assertEqual(field.check(databases=self.databases), [])
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index 29f472b85b..b7b199d8f1 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -971,6 +971,23 @@ class WriterTests(SimpleTestCase):
("('models.Model', {'from django.db import models'})", set()),
)
+ def test_database_on_delete_serializer_value(self):
+ db_level_on_delete_options = [
+ models.DB_CASCADE,
+ models.DB_SET_DEFAULT,
+ models.DB_SET_NULL,
+ ]
+ for option in db_level_on_delete_options:
+ self.assertSerializedEqual(option)
+ self.assertSerializedResultEqual(
+ MigrationWriter.serialize(option),
+ (
+ f"('django.db.models.deletion.{option.__name__}', "
+ "{'import django.db.models.deletion'})",
+ set(),
+ ),
+ )
+
def test_simple_migration(self):
"""
Tests serializing a simple migration.
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 88d4ebbc8b..ab8b07e9d3 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -18,6 +18,8 @@ from django.db import (
from django.db.backends.utils import truncate_name
from django.db.models import (
CASCADE,
+ DB_CASCADE,
+ DB_SET_NULL,
PROTECT,
AutoField,
BigAutoField,
@@ -411,6 +413,40 @@ class SchemaTests(TransactionTestCase):
)
@skipUnlessDBFeature("can_create_inline_fk")
+ def test_inline_fk_db_on_delete(self):
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ editor.create_model(Book)
+ editor.create_model(Note)
+ self.assertForeignKeyNotExists(Note, "book_id", "schema_book")
+ # Add a foreign key from model to the other.
+ with (
+ CaptureQueriesContext(connection) as ctx,
+ connection.schema_editor() as editor,
+ ):
+ new_field = ForeignKey(Book, DB_CASCADE)
+ new_field.set_attributes_from_name("book")
+ editor.add_field(Note, new_field)
+ self.assertForeignKeyExists(Note, "book_id", "schema_book")
+ # Creating a FK field with a constraint uses a single statement without
+ # a deferred ALTER TABLE.
+ self.assertFalse(
+ [
+ sql
+ for sql in (str(statement) for statement in editor.deferred_sql)
+ if sql.startswith("ALTER TABLE") and "ADD CONSTRAINT" in sql
+ ]
+ )
+ # ON DELETE clause is used.
+ self.assertTrue(
+ any(
+ capture_query["sql"].startswith("ALTER TABLE")
+ and "ON DELETE" in capture_query["sql"]
+ for capture_query in ctx.captured_queries
+ )
+ )
+
+ @skipUnlessDBFeature("can_create_inline_fk")
def test_add_inline_fk_update_data(self):
with connection.schema_editor() as editor:
editor.create_model(Node)
@@ -566,6 +602,63 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(Author, new_field2, new_field, strict=True)
self.assertForeignKeyNotExists(Author, "tag_id", "schema_tag")
+ @skipUnlessDBFeature("supports_foreign_keys", "can_introspect_foreign_keys")
+ def test_fk_alter_on_delete(self):
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ editor.create_model(Book)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ # Change CASCADE to DB_CASCADE.
+ old_field = Book._meta.get_field("author")
+ new_field = ForeignKey(Author, DB_CASCADE)
+ new_field.set_attributes_from_name("author")
+ with (
+ connection.schema_editor() as editor,
+ CaptureQueriesContext(connection) as ctx,
+ ):
+ editor.alter_field(Book, old_field, new_field)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), True
+ )
+ # Change DB_CASCADE to CASCADE.
+ old_field = new_field
+ new_field = ForeignKey(Author, CASCADE)
+ new_field.set_attributes_from_name("author")
+ with (
+ connection.schema_editor() as editor,
+ CaptureQueriesContext(connection) as ctx,
+ ):
+ editor.alter_field(Book, old_field, new_field)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), False
+ )
+
+ @isolate_apps("schema")
+ @skipUnlessDBFeature("supports_foreign_keys", "can_introspect_foreign_keys")
+ def test_create_model_db_on_delete(self):
+ class Parent(Model):
+ class Meta:
+ app_label = "schema"
+
+ class Child(Model):
+ parent_fk = ForeignKey(Parent, DB_SET_NULL, null=True)
+
+ class Meta:
+ app_label = "schema"
+
+ with connection.schema_editor() as editor:
+ editor.create_model(Parent)
+ with CaptureQueriesContext(connection) as ctx:
+ with connection.schema_editor() as editor:
+ editor.create_model(Child)
+
+ self.assertForeignKeyNotExists(Child, "parent_id", "schema_parent")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), True
+ )
+
@isolate_apps("schema")
def test_no_db_constraint_added_during_primary_key_change(self):
"""
@@ -4598,6 +4691,7 @@ class SchemaTests(TransactionTestCase):
"to_table": editor.quote_name(table),
"to_column": editor.quote_name(model._meta.auto_field.column),
"deferrable": connection.ops.deferrable_sql(),
+ "on_delete_db": "",
}
)
self.assertIn(
@@ -4784,7 +4878,7 @@ class SchemaTests(TransactionTestCase):
error_messages={"invalid": "error message"},
help_text="help text",
limit_choices_to={"limit": "choice"},
- on_delete=PROTECT,
+ on_delete=CASCADE,
related_name="related_name",
related_query_name="related_query_name",
validators=[lambda x: x],