summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/models/deletion.py6
-rw-r--r--tests/generic_relations_regress/models.py24
-rw-r--r--tests/generic_relations_regress/tests.py15
3 files changed, 41 insertions, 4 deletions
diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py
index bed3913fb0..e3c38a03cc 100644
--- a/django/db/models/deletion.py
+++ b/django/db/models/deletion.py
@@ -138,9 +138,9 @@ class Collector(object):
include_hidden=True, include_proxy_eq=True):
if related.field.rel.on_delete is not DO_NOTHING:
return False
- # GFK deletes
- for relation in opts.many_to_many:
- if not relation.rel.through:
+ for field in model._meta.virtual_fields:
+ if hasattr(field, 'bulk_related_objects'):
+ # It's something like generic foreign key.
return False
return True
diff --git a/tests/generic_relations_regress/models.py b/tests/generic_relations_regress/models.py
index a51dffb955..b57b887e4a 100644
--- a/tests/generic_relations_regress/models.py
+++ b/tests/generic_relations_regress/models.py
@@ -4,6 +4,7 @@ from django.contrib.contenttypes.fields import (
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
+from django.db.models.deletion import ProtectedError
__all__ = ('Link', 'Place', 'Restaurant', 'Person', 'Address',
@@ -192,3 +193,26 @@ class D(models.Model):
class Meta:
ordering = ('id',)
+
+
+# Ticket #22998
+
+class Node(models.Model):
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ content = GenericForeignKey('content_type', 'object_id')
+
+
+class Content(models.Model):
+ nodes = GenericRelation(Node)
+ related_obj = models.ForeignKey('Related', on_delete=models.CASCADE)
+
+
+class Related(models.Model):
+ pass
+
+
+def prevent_deletes(sender, instance, **kwargs):
+ raise ProtectedError("Not allowed to delete.", [instance])
+
+models.signals.pre_delete.connect(prevent_deletes, sender=Node)
diff --git a/tests/generic_relations_regress/tests.py b/tests/generic_relations_regress/tests.py
index 481101f83f..144a67f106 100644
--- a/tests/generic_relations_regress/tests.py
+++ b/tests/generic_relations_regress/tests.py
@@ -2,11 +2,14 @@ from django.db.models import Q, Sum
from django.db.utils import IntegrityError
from django.test import TestCase, skipIfDBFeature
from django.forms.models import modelform_factory
+from django.db.models.deletion import ProtectedError
from .models import (
Address, Place, Restaurant, Link, CharLink, TextLink,
Person, Contact, Note, Organization, OddRelation1, OddRelation2, Company,
- Developer, Team, Guild, Tag, Board, HasLinkThing, A, B, C, D)
+ Developer, Team, Guild, Tag, Board, HasLinkThing, A, B, C, D,
+ Related, Content, Node,
+)
class GenericRelationTests(TestCase):
@@ -247,3 +250,13 @@ class GenericRelationTests(TestCase):
form.save()
links = HasLinkThing._meta.get_field_by_name('links')[0]
self.assertEqual(links.save_form_data_calls, 1)
+
+ def test_ticket_22998(self):
+ related = Related.objects.create()
+ content = Content.objects.create(related_obj=related)
+ node = Node.objects.create(content=content)
+
+ # deleting the Related cascades to the Content cascades to the Node,
+ # where the pre_delete signal should fire and prevent deletion.
+ with self.assertRaises(ProtectedError):
+ related.delete()