mirror of https://github.com/django/django.git
[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
|
||||
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:
|
||||
if field.is_relation:
|
||||
if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT:
|
||||
continue
|
||||
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
|
||||
related_models.add((app_label, model_name))
|
||||
|
|
|
@ -63,6 +63,9 @@ Bugfixes
|
|||
* Fixed JavaScript path of ``contrib.admin``’s related field widget when using
|
||||
alternate static file storages (:ticket:`24655`).
|
||||
|
||||
* Fixed a migration crash when adding new relations to models
|
||||
(:ticket:`24573`).
|
||||
|
||||
Optimizations
|
||||
=============
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.apps.registry import Apps
|
||||
from django.db import models
|
||||
from django.db.migrations.operations import (
|
||||
AlterField, DeleteModel, RemoveField,
|
||||
AddField, AlterField, DeleteModel, RemoveField,
|
||||
)
|
||||
from django.db.migrations.state import (
|
||||
InvalidBasesError, ModelState, ProjectState, get_related_models_recursive,
|
||||
|
@ -368,6 +368,57 @@ class StateTests(TestCase):
|
|||
project_state.add_model(ModelState.from_model(B))
|
||||
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):
|
||||
"""
|
||||
#24225 - Tests that relations between models are updated while
|
||||
|
|
Loading…
Reference in New Issue