Skip to content

Another cascading bug on CASCADE deletion #229

@godardth

Description

@godardth

Hi,

I have an issue in django-polymorphic when deleting models from django-admin.

Models are defined as below

class Farm(models.Model):
    class Meta:
        pass

class Animal(PolymorphicModel):
    farm = models.ForeignKey('Farm', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    class Meta:
        pass

class Dog(Animal):
    dog_param = models.CharField(max_length=100)
    class Meta:
        pass

class Cat(Animal):
    cat_param = models.CharField(max_length=100)
    class Meta:
        pass

Now I am creating a Farm object with both a Dog and a Cat (problem doesn't appear if all polymorphic related objects are of the same sub-class.

When trying to delete the Farm object in admin, I get the below hierarchy

  • Farm: Farm number 19
    • Dog: 37 - dog
    • Cat: 38 - cat
  • Animal: 37 - dog
  • Animal: 38 - cat

And when confirming the deletion, I get the error below

Internal Server Error: /admin/farming/farm/
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 149, in get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 147, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 541, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 149, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py", line 244, in inner
    return view(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 67, in _wrapper
    return bound_func(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 149, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 63, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 1512, in changelist_view
    response = self.response_action(request, queryset=cl.get_queryset(request))
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 1245, in response_action
    response = func(self, request, queryset)
  File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/actions.py", line 49, in delete_selected
    queryset.delete()
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 600, in delete
    deleted, _rows_count = collector.delete()
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/deletion.py", line 308, in delete
    for model, instances in six.iteritems(self.data):
  File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py", line 223, in __exit__
    connection.commit()
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 242, in commit
    self._commit()
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 211, in _commit
    return self.connection.commit()
  File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 95, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/usr/local/lib/python2.7/dist-packages/django/db/backends/base/base.py", line 211, in _commit
    return self.connection.commit()
IntegrityError: update or delete on table "farming_animal" violates foreign key constraint "farming_cat_animal_ptr_id_77dae4b8_fk_farming_animal_id" on table "farming_cat"
DETAIL:  Key (id)=(38) is still referenced from table "farming_cat".

I tracked the problem down to be a problem in the deletion Collector class where related object to Farm (i.e. Animal) are of the sub-classes either Dog or Cat. So in the case above, we try to delete the Cat object from the Dog table.

I solved my problem by using the _base_manager property of the Model class . And referring to a non polymorphic object manager like below

class Animal(PolymorphicModel):
    instance = models.ForeignKey('Farm', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    _base_manager = models.Manager()
    class Meta:
        pass

Now when trying to delete the Farm object in admin I get the correct hierarchy

I am using the below

psql 9.3.11
python 2.7.6
django 1.9.8
django-polymorphic 0.9.2

My thought would be to add _base_manager = models.Manager() in the django-polymorphic PolymorphicModel. What do you guy think about this ?

Thanks,
Theo

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions