[1.8.x] Fixed #24573 -- Considered new related models for reloading
Thanks tttomekkk for the report.
Backport of b93690c465
from master
This commit is contained in:
parent
697317f334
commit
0cacb8f8ba
|
@ -101,12 +101,25 @@ class ProjectState(object):
|
||||||
|
|
||||||
# Get all outgoing references from the model to be rendered
|
# Get all outgoing references from the model to be rendered
|
||||||
model_state = self.models[(app_label, model_name)]
|
model_state = self.models[(app_label, model_name)]
|
||||||
|
# Directly related models are the models pointed to by ForeignKeys,
|
||||||
|
# OneToOneFields, and ManyToManyFields.
|
||||||
|
direct_related_models = set()
|
||||||
for name, field in model_state.fields:
|
for name, field in model_state.fields:
|
||||||
if field.is_relation:
|
if field.is_relation:
|
||||||
if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT:
|
if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT:
|
||||||
continue
|
continue
|
||||||
rel_app_label, rel_model_name = _get_app_label_and_model_name(field.rel.to, app_label)
|
rel_app_label, rel_model_name = _get_app_label_and_model_name(field.rel.to, app_label)
|
||||||
related_models.add((rel_app_label, rel_model_name.lower()))
|
direct_related_models.add((rel_app_label, rel_model_name.lower()))
|
||||||
|
|
||||||
|
# For all direct related models recursively get all related models.
|
||||||
|
related_models.update(direct_related_models)
|
||||||
|
for rel_app_label, rel_model_name in direct_related_models:
|
||||||
|
try:
|
||||||
|
rel_model = self.apps.get_model(rel_app_label, rel_model_name)
|
||||||
|
except LookupError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
related_models.update(get_related_models_recursive(rel_model))
|
||||||
|
|
||||||
# Include the model itself
|
# Include the model itself
|
||||||
related_models.add((app_label, model_name))
|
related_models.add((app_label, model_name))
|
||||||
|
|
|
@ -63,6 +63,9 @@ Bugfixes
|
||||||
* Fixed JavaScript path of ``contrib.admin``’s related field widget when using
|
* Fixed JavaScript path of ``contrib.admin``’s related field widget when using
|
||||||
alternate static file storages (:ticket:`24655`).
|
alternate static file storages (:ticket:`24655`).
|
||||||
|
|
||||||
|
* Fixed a migration crash when adding new relations to models
|
||||||
|
(:ticket:`24573`).
|
||||||
|
|
||||||
Optimizations
|
Optimizations
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.apps.registry import Apps
|
from django.apps.registry import Apps
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.migrations.operations import (
|
from django.db.migrations.operations import (
|
||||||
AlterField, DeleteModel, RemoveField,
|
AddField, AlterField, DeleteModel, RemoveField,
|
||||||
)
|
)
|
||||||
from django.db.migrations.state import (
|
from django.db.migrations.state import (
|
||||||
InvalidBasesError, ModelState, ProjectState, get_related_models_recursive,
|
InvalidBasesError, ModelState, ProjectState, get_related_models_recursive,
|
||||||
|
@ -368,6 +368,57 @@ class StateTests(TestCase):
|
||||||
project_state.add_model(ModelState.from_model(B))
|
project_state.add_model(ModelState.from_model(B))
|
||||||
self.assertEqual(len(project_state.apps.get_models()), 2)
|
self.assertEqual(len(project_state.apps.get_models()), 2)
|
||||||
|
|
||||||
|
def test_add_relations(self):
|
||||||
|
"""
|
||||||
|
#24573 - Adding relations to existing models should reload the
|
||||||
|
referenced models too.
|
||||||
|
"""
|
||||||
|
class A(models.Model):
|
||||||
|
class Meta:
|
||||||
|
app_label = 'something'
|
||||||
|
|
||||||
|
class B(A):
|
||||||
|
class Meta:
|
||||||
|
app_label = 'something'
|
||||||
|
|
||||||
|
class C(models.Model):
|
||||||
|
class Meta:
|
||||||
|
app_label = 'something'
|
||||||
|
|
||||||
|
project_state = ProjectState()
|
||||||
|
project_state.add_model(ModelState.from_model(A))
|
||||||
|
project_state.add_model(ModelState.from_model(B))
|
||||||
|
project_state.add_model(ModelState.from_model(C))
|
||||||
|
|
||||||
|
project_state.apps # We need to work with rendered models
|
||||||
|
|
||||||
|
old_state = project_state.clone()
|
||||||
|
model_a_old = old_state.apps.get_model('something', 'A')
|
||||||
|
model_b_old = old_state.apps.get_model('something', 'B')
|
||||||
|
model_c_old = old_state.apps.get_model('something', 'C')
|
||||||
|
# Check that the relations between the old models are correct
|
||||||
|
self.assertIs(model_a_old._meta.get_field('b').related_model, model_b_old)
|
||||||
|
self.assertIs(model_b_old._meta.get_field('a_ptr').related_model, model_a_old)
|
||||||
|
|
||||||
|
operation = AddField('c', 'to_a', models.OneToOneField('something.A', related_name='from_c'))
|
||||||
|
operation.state_forwards('something', project_state)
|
||||||
|
model_a_new = project_state.apps.get_model('something', 'A')
|
||||||
|
model_b_new = project_state.apps.get_model('something', 'B')
|
||||||
|
model_c_new = project_state.apps.get_model('something', 'C')
|
||||||
|
|
||||||
|
# Check that all models have changed
|
||||||
|
self.assertIsNot(model_a_old, model_a_new)
|
||||||
|
self.assertIsNot(model_b_old, model_b_new)
|
||||||
|
self.assertIsNot(model_c_old, model_c_new)
|
||||||
|
# Check that the relations between the old models still hold
|
||||||
|
self.assertIs(model_a_old._meta.get_field('b').related_model, model_b_old)
|
||||||
|
self.assertIs(model_b_old._meta.get_field('a_ptr').related_model, model_a_old)
|
||||||
|
# Check that the relations between the new models correct
|
||||||
|
self.assertIs(model_a_new._meta.get_field('b').related_model, model_b_new)
|
||||||
|
self.assertIs(model_b_new._meta.get_field('a_ptr').related_model, model_a_new)
|
||||||
|
self.assertIs(model_a_new._meta.get_field('from_c').related_model, model_c_new)
|
||||||
|
self.assertIs(model_c_new._meta.get_field('to_a').related_model, model_a_new)
|
||||||
|
|
||||||
def test_remove_relations(self):
|
def test_remove_relations(self):
|
||||||
"""
|
"""
|
||||||
#24225 - Tests that relations between models are updated while
|
#24225 - Tests that relations between models are updated while
|
||||||
|
|
Loading…
Reference in New Issue