Fixed #20401 -- ContentTypeManager.get_for_model reads from db_for_read.
Thanks Simon Charette and Tim Graham for the reviews.
This commit is contained in:
parent
d240b29c08
commit
62f9508ade
|
@ -38,18 +38,27 @@ class ContentTypeManager(models.Manager):
|
||||||
"""
|
"""
|
||||||
opts = self._get_opts(model, for_concrete_model)
|
opts = self._get_opts(model, for_concrete_model)
|
||||||
try:
|
try:
|
||||||
ct = self._get_from_cache(opts)
|
return self._get_from_cache(opts)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# Load or create the ContentType entry. The smart_text() is
|
pass
|
||||||
# needed around opts.verbose_name_raw because name_raw might be a
|
|
||||||
# django.utils.functional.__proxy__ object.
|
# The ContentType entry was not found in the cache, therefore we
|
||||||
|
# proceed to load or create it.
|
||||||
|
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 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.
|
||||||
|
# The smart_text() is needed around opts.verbose_name_raw because
|
||||||
|
# name_raw might be a django.utils.functional.__proxy__ object.
|
||||||
ct, created = self.get_or_create(
|
ct, created = self.get_or_create(
|
||||||
app_label=opts.app_label,
|
app_label=opts.app_label,
|
||||||
model=opts.model_name,
|
model=opts.model_name,
|
||||||
defaults={'name': smart_text(opts.verbose_name_raw)},
|
defaults={'name': smart_text(opts.verbose_name_raw)},
|
||||||
)
|
)
|
||||||
self._add_to_cache(self.db, ct)
|
self._add_to_cache(self.db, ct)
|
||||||
|
|
||||||
return ct
|
return ct
|
||||||
|
|
||||||
def get_for_models(self, *models, **kwargs):
|
def get_for_models(self, *models, **kwargs):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.contrib.contenttypes.fields import (
|
||||||
)
|
)
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core import checks
|
from django.core import checks
|
||||||
from django.db import models
|
from django.db import connections, models, router
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str
|
||||||
|
@ -335,3 +335,40 @@ class GenericRelationshipTests(IsolatedModelsTestCase):
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
self.assertEqual(errors, expected)
|
self.assertEqual(errors, expected)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRouter(object):
|
||||||
|
def db_for_read(self, model, **hints):
|
||||||
|
return 'other'
|
||||||
|
|
||||||
|
def db_for_write(self, model, **hints):
|
||||||
|
return 'default'
|
||||||
|
|
||||||
|
|
||||||
|
class ContentTypesMultidbTestCase(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.old_routers = router.routers
|
||||||
|
router.routers = [TestRouter()]
|
||||||
|
|
||||||
|
# Whenever a test starts executing, only the "default" database is
|
||||||
|
# connected. We explicitly connect to the "other" database here. If we
|
||||||
|
# don't do it, then it will be implicitly connected later when we query
|
||||||
|
# it, but in that case some database backends may automatically perform
|
||||||
|
# extra queries upon connecting (notably mysql executes
|
||||||
|
# "SET SQL_AUTO_IS_NULL = 0"), which will affect assertNumQueries().
|
||||||
|
connections['other'].ensure_connection()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
router.routers = self.old_routers
|
||||||
|
|
||||||
|
def test_multidb(self):
|
||||||
|
"""
|
||||||
|
Test that, when using multiple databases, we use the db_for_read (see
|
||||||
|
#20401).
|
||||||
|
"""
|
||||||
|
ContentType.objects.clear_cache()
|
||||||
|
|
||||||
|
with self.assertNumQueries(0, using='default'), \
|
||||||
|
self.assertNumQueries(1, using='other'):
|
||||||
|
ContentType.objects.get_for_model(Author)
|
||||||
|
|
Loading…
Reference in New Issue