Loading django/contrib/contenttypes/models.py +13 −12 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import warnings from django.apps import apps from django.db import models from django.db.utils import OperationalError, ProgrammingError from django.db.utils import IntegrityError, OperationalError, ProgrammingError from django.utils.deprecation import RemovedInDjango20Warning from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -58,18 +58,11 @@ class ContentTypeManager(models.Manager): # The ContentType entry was not found in the cache, therefore we # proceed to load or create it. try: try: # We start with get() and not get_or_create() in order to use # the db_for_read (see #20401). ct = self.get(app_label=opts.app_label, model=opts.model_name) except (OperationalError, ProgrammingError): # It's possible to migrate a single app before contenttypes, # as it's not a required initial dependency (it's contrib!) # Have a nice error for this. raise RuntimeError( "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ) except self.model.DoesNotExist: # Not found in the database; we proceed to create it. This time we # use get_or_create to take care of any race conditions. Loading @@ -77,6 +70,14 @@ class ContentTypeManager(models.Manager): app_label=opts.app_label, model=opts.model_name, ) except (OperationalError, ProgrammingError, IntegrityError): # It's possible to migrate a single app before contenttypes, # as it's not a required initial dependency (it's contrib!) # Have a nice error for this. raise RuntimeError( "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ) self._add_to_cache(self.db, ct) return ct Loading django/contrib/contenttypes/tests/tests.py +25 −1 Original line number Diff line number Diff line Loading @@ -5,8 +5,9 @@ import warnings from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.views import shortcut from django.contrib.sites.shortcuts import get_current_site from django.db.utils import IntegrityError, OperationalError, ProgrammingError from django.http import Http404, HttpRequest from django.test import TestCase, override_settings from django.test import TestCase, mock, override_settings from django.utils import six from .models import ( Loading Loading @@ -264,3 +265,26 @@ class ContentTypesTests(TestCase): "ContentType.name field doesn't exist any longer. Please remove it from your code." ) self.assertTrue(ContentType.objects.filter(model='OldModel').exists()) @mock.patch('django.contrib.contenttypes.models.ContentTypeManager.get_or_create') @mock.patch('django.contrib.contenttypes.models.ContentTypeManager.get') def test_message_if_get_for_model_fails(self, mocked_get, mocked_get_or_create): """ Check that `RuntimeError` with nice error message is raised if `get_for_model` fails because of database errors. """ def _test_message(mocked_method): for ExceptionClass in (IntegrityError, OperationalError, ProgrammingError): mocked_method.side_effect = ExceptionClass with self.assertRaisesMessage( RuntimeError, "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ): ContentType.objects.get_for_model(ContentType) _test_message(mocked_get) mocked_get.side_effect = ContentType.DoesNotExist _test_message(mocked_get_or_create) Loading
django/contrib/contenttypes/models.py +13 −12 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import warnings from django.apps import apps from django.db import models from django.db.utils import OperationalError, ProgrammingError from django.db.utils import IntegrityError, OperationalError, ProgrammingError from django.utils.deprecation import RemovedInDjango20Warning from django.utils.encoding import force_text, python_2_unicode_compatible from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -58,18 +58,11 @@ class ContentTypeManager(models.Manager): # The ContentType entry was not found in the cache, therefore we # proceed to load or create it. try: try: # We start with get() and not get_or_create() in order to use # the db_for_read (see #20401). ct = self.get(app_label=opts.app_label, model=opts.model_name) except (OperationalError, ProgrammingError): # It's possible to migrate a single app before contenttypes, # as it's not a required initial dependency (it's contrib!) # Have a nice error for this. raise RuntimeError( "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ) except self.model.DoesNotExist: # Not found in the database; we proceed to create it. This time we # use get_or_create to take care of any race conditions. Loading @@ -77,6 +70,14 @@ class ContentTypeManager(models.Manager): app_label=opts.app_label, model=opts.model_name, ) except (OperationalError, ProgrammingError, IntegrityError): # It's possible to migrate a single app before contenttypes, # as it's not a required initial dependency (it's contrib!) # Have a nice error for this. raise RuntimeError( "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ) self._add_to_cache(self.db, ct) return ct Loading
django/contrib/contenttypes/tests/tests.py +25 −1 Original line number Diff line number Diff line Loading @@ -5,8 +5,9 @@ import warnings from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.views import shortcut from django.contrib.sites.shortcuts import get_current_site from django.db.utils import IntegrityError, OperationalError, ProgrammingError from django.http import Http404, HttpRequest from django.test import TestCase, override_settings from django.test import TestCase, mock, override_settings from django.utils import six from .models import ( Loading Loading @@ -264,3 +265,26 @@ class ContentTypesTests(TestCase): "ContentType.name field doesn't exist any longer. Please remove it from your code." ) self.assertTrue(ContentType.objects.filter(model='OldModel').exists()) @mock.patch('django.contrib.contenttypes.models.ContentTypeManager.get_or_create') @mock.patch('django.contrib.contenttypes.models.ContentTypeManager.get') def test_message_if_get_for_model_fails(self, mocked_get, mocked_get_or_create): """ Check that `RuntimeError` with nice error message is raised if `get_for_model` fails because of database errors. """ def _test_message(mocked_method): for ExceptionClass in (IntegrityError, OperationalError, ProgrammingError): mocked_method.side_effect = ExceptionClass with self.assertRaisesMessage( RuntimeError, "Error creating new content types. Please make sure contenttypes " "is migrated before trying to migrate apps individually." ): ContentType.objects.get_for_model(ContentType) _test_message(mocked_get) mocked_get.side_effect = ContentType.DoesNotExist _test_message(mocked_get_or_create)