Search code examples
pythondjangopython-3.xdjango-modelsdjango-polymorphic

Django-PolymorphicModels - Error when deleting an instance


It's the first time I'm trying 'PolymorphicModel', maybe there is something I'm doing wrong or I'm trying to do something that is not supported. Is there anyway to get around this?

My simplified model:

from django.polymorphic import PolymorphicModel


class Question(PolymorphicModel):
    description = models.TextField(default='')

    compound_question = models.ForeignKey('CompoundQuestion',
                                          on_delete=models.CASCADE,
                                          blank=True,
                                          null=True,
                                          related_name='sub_questions')

    bonus_question = models.OneToOneField('BonusQuestion',
                                          on_delete=models.CASCADE,
                                          blank=True,
                                          null=True,
                                          related_name='question')


class SimpleQuestion(Question):
    pass


class CompoundQuestion(Question):
    pass


class BonusQuestion(Question):
    pass

If I create the necessary instances,

compound_q = CompoundQuestion()
compound_q.save()
simple_q2 = SimpleQuestion(compound_question=compound_q)
simple_q2.save()
bonus_q = BonusQuestion(compound_question=compound_q)
bonus_q.save()
simple_q1 = SimpleQuestion(bonus_question=bonus_q)
simple_q1.save()

so that in the end I end up with:

compound_q.sub_questions.all()
>>> <PolymorphicQuerySet [<BonusQuestion: BonusQuestion object (5)>, <SimpleQuestion: SimpleQuestion object (8)>]>

After I do compound_q.delete() I get:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/base.py", line 936, in delete
    collector.collect([self], keep_parents=keep_parents)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/deletion.py", line 245, in collect
    field.remote_field.on_delete(self, field, sub_objs, self.using)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/deletion.py", line 17, in CASCADE
    source_attr=field.name, nullable=field.null)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/deletion.py", line 226, in collect
    sub_objs = self.related_objects(related, batch)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/deletion.py", line 257, in related_objects
    **{"%s__in" % related.field.name: objs}
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/query.py", line 904, in filter
    return self._filter_or_exclude(False, *args, **kwargs)
  File ".../Python/Django/env/lib/python3.6/site-packages/polymorphic/query.py", line 173, in _filter_or_exclude
    negate, *(list(q_objects) + additional_args), **kwargs
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/query.py", line 923, in _filter_or_exclude
    clone.query.add_q(Q(*args, **kwargs))
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1340, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1371, in _add_q
    check_filterable=check_filterable,
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1274, in build_filter
    self.check_related_objects(join_info.final_field, value, join_info.opts)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1115, in check_related_objects
    self.check_query_object_type(v, opts, field)
  File ".../Python/Django/env/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1095, in check_query_object_type
    (value, opts.object_name))
ValueError: Cannot query "SimpleQuestion object (8)": Must be "BonusQuestion" instance.

Is there something wrong with my model? Everything else seems to be working as expected. Thanks for reading :)


Solution

  • This appears to be a known bug in the django-polymorphic package. There is a work around suggested here to add a vanilla Manager to your class and to set this manager as the default

    class Question(PolymorphicModel):
    
        non_polymorphic = models.Manager()
    
        class Meta
            base_manager_name = 'non_polymorphic'