1
0
mirror of https://github.com/django/django.git synced 2024-12-22 09:05:43 +00:00

Fixed #35545, Refs #32833 -- Fixed ContentTypeManager.get_for_models() crash in CreateModel migrations.

Thank you to Csirmaz Bendegúz for the report and Simon Charettes for the review.
This commit is contained in:
Sarah Boyce 2024-06-21 14:24:25 +02:00
parent 2a082d827d
commit f1705c8780
2 changed files with 24 additions and 10 deletions

View File

@ -75,7 +75,7 @@ class ContentTypeManager(models.Manager):
ct = self._get_from_cache(opts)
except KeyError:
needed_models[opts.app_label].add(opts.model_name)
needed_opts[opts].append(model)
needed_opts[(opts.app_label, opts.model_name)].append(model)
else:
results[model] = ct
if needed_opts:
@ -89,18 +89,13 @@ class ContentTypeManager(models.Manager):
)
cts = self.filter(condition)
for ct in cts:
opts_models = needed_opts.pop(
ct._meta.apps.get_model(ct.app_label, ct.model)._meta, []
)
opts_models = needed_opts.pop((ct.app_label, ct.model), [])
for model in opts_models:
results[model] = ct
self._add_to_cache(self.db, ct)
# Create content types that weren't in the cache or DB.
for opts, opts_models in needed_opts.items():
ct = self.create(
app_label=opts.app_label,
model=opts.model_name,
)
for (app_label, model_name), opts_models in needed_opts.items():
ct = self.create(app_label=app_label, model=model_name)
self._add_to_cache(self.db, ct)
for model in opts_models:
results[model] = ct

View File

@ -2,7 +2,7 @@ from django.apps import apps
from django.contrib.contenttypes.models import ContentType, ContentTypeManager
from django.contrib.contenttypes.prefetch import GenericPrefetch
from django.db import models
from django.db.migrations.state import ProjectState
from django.db.migrations.state import ModelState, ProjectState
from django.test import TestCase, override_settings
from django.test.utils import isolate_apps
@ -99,6 +99,25 @@ class ContentTypesTests(TestCase):
cts, {ContentType: ContentType.objects.get_for_model(ContentType)}
)
@isolate_apps("contenttypes_tests")
def test_get_for_models_migrations_create_model(self):
state = ProjectState.from_apps(apps.get_app_config("contenttypes"))
class Foo(models.Model):
class Meta:
app_label = "contenttypes_tests"
state.add_model(ModelState.from_model(Foo))
ContentType = state.apps.get_model("contenttypes", "ContentType")
cts = ContentType.objects.get_for_models(FooWithUrl, Foo)
self.assertEqual(
cts,
{
Foo: ContentType.objects.get_for_model(Foo),
FooWithUrl: ContentType.objects.get_for_model(FooWithUrl),
},
)
def test_get_for_models_full_cache(self):
# Full cache
ContentType.objects.get_for_model(ContentType)