From fb8eed78ad604a0db7ae221de79a1b6ff6c88286 Mon Sep 17 00:00:00 2001 From: Diederik van der Boor Date: Tue, 1 Aug 2017 11:38:36 +0200 Subject: [PATCH] Provide a better error message when polymorphic_ctype_id is Null refs #51, #140, #304 --- polymorphic/models.py | 11 +++++++++++ polymorphic/tests/test_orm.py | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/polymorphic/models.py b/polymorphic/models.py index f0af431..4759d0a 100644 --- a/polymorphic/models.py +++ b/polymorphic/models.py @@ -17,6 +17,10 @@ from .query_translate import translate_polymorphic_Q_object # PolymorphicModel +class PolymorphicTypeUndefined(LookupError): + pass + + class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)): """ Abstract base class that provides polymorphic behaviour @@ -82,6 +86,13 @@ class PolymorphicModel(six.with_metaclass(PolymorphicModelBase, models.Model)): retrieve objects, then the real class/type of these objects may be determined using this method. """ + if self.polymorphic_ctype_id is None: + raise PolymorphicTypeUndefined(( + "The model {}#{} does not have a `polymorphic_ctype_id` value defined.\n" + "If you created models outside polymorphic, e.g. through an import or migration, " + "make sure the `polymorphic_ctype_id` field points to the ContentType ID of the model subclass." + ).format(self.__class__.__name__, self.pk)) + # the following line would be the easiest way to do this, but it produces sql queries # return self.polymorphic_ctype.model_class() # so we use the following version, which uses the ContentType manager cache. diff --git a/polymorphic/tests/test_orm.py b/polymorphic/tests/test_orm.py index e190adc..63742a3 100644 --- a/polymorphic/tests/test_orm.py +++ b/polymorphic/tests/test_orm.py @@ -4,6 +4,8 @@ import django from django.db.models import Case, Count, Q, When from django.test import TestCase from django.utils import six + +from polymorphic.models import PolymorphicTypeUndefined from polymorphic.tests import * # all models @@ -765,6 +767,16 @@ class PolymorphicTests(TestCase): result = Model2B.objects.annotate(val=Concat('field1', 'field2')) self.assertEqual(list(result), []) + def test_null_polymorphic_id(self): + """Test that a proper error message is displayed when the database lacks the ``polymorphic_ctype_id``""" + Model2A.objects.create(field1='A1') + Model2B.objects.create(field1='A1', field2='B2') + Model2B.objects.create(field1='A1', field2='B2') + Model2A.objects.all().update(polymorphic_ctype_id=None) + + with self.assertRaises(PolymorphicTypeUndefined): + list(Model2A.objects.all()) + def qrepr(data): """