diff --git a/polymorphic/models.py b/polymorphic/models.py index 4d8f6937..845209cb 100644 --- a/polymorphic/models.py +++ b/polymorphic/models.py @@ -157,6 +157,10 @@ def get_real_instance(self): retrieve objects, then the complete object with it's real class/type and all fields may be retrieved with this method. + If the model of the object's actual type does not exist (i.e. its + ContentType is stale), this method raises a + :class:`~polymorphic.models.PolymorphicTypeInvalid` exception. + .. note:: Each method call executes one db query (if necessary). Use the :meth:`~polymorphic.managers.PolymorphicQuerySet.get_real_instances` @@ -165,6 +169,11 @@ def get_real_instance(self): real_model = self.get_real_instance_class() if real_model == self.__class__: return self + if real_model is None: + raise PolymorphicTypeInvalid( + f"ContentType {self.polymorphic_ctype_id} for {self.__class__} " + f"#{self.pk} does not have a corresponding model!" + ) return real_model.objects.db_manager(self._state.db).get(pk=self.pk) def __init__(self, *args, **kwargs): diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index 1f2de936..5e655552 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -321,6 +321,15 @@ def test_manual_get_real_instance(self): o = Model2A.objects.non_polymorphic().get(field1="C1") assert o.get_real_instance().__class__ == Model2C + def test_get_real_instance_with_stale_content_type(self): + ctype = ContentType.objects.create(app_label="tests", model="stale") + o = Model2A.objects.create(field1="A1", polymorphic_ctype=ctype) + + assert o.get_real_instance_class() is None + match = "does not have a corresponding model" + with pytest.raises(PolymorphicTypeInvalid, match=match): + o.get_real_instance() + def test_non_polymorphic(self): self.create_model2abcd()