Skip to content

Commit

Permalink
Fixed #22998 -- Updated the fast_delete logic for GFKs
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinwahl authored and akaariai committed Jul 16, 2014
1 parent 28efafa commit 6e2b82f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
6 changes: 3 additions & 3 deletions django/db/models/deletion.py
Expand Up @@ -138,9 +138,9 @@ def can_fast_delete(self, objs, from_field=None):
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

Expand Down
24 changes: 24 additions & 0 deletions tests/generic_relations_regress/models.py
Expand Up @@ -4,6 +4,7 @@
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',
Expand Down Expand Up @@ -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)
15 changes: 14 additions & 1 deletion tests/generic_relations_regress/tests.py
Expand Up @@ -2,11 +2,14 @@
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):
Expand Down Expand Up @@ -247,3 +250,13 @@ def test_editable_generic_rel(self):
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()

0 comments on commit 6e2b82f

Please sign in to comment.