diff --git a/django/db/models/options.py b/django/db/models/options.py index d39873fd70..14f73c301f 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -9,7 +9,7 @@ from django.conf import settings from django.db.models.fields.related import ManyToManyRel from django.db.models.fields import AutoField, FieldDoesNotExist from django.db.models.fields.proxy import OrderWrt -from django.db.models.loading import get_models, app_cache_ready, cache +from django.db.models.loading import app_cache_ready, cache from django.utils import six from django.utils.functional import cached_property from django.utils.encoding import force_text, smart_text, python_2_unicode_compatible @@ -495,7 +495,7 @@ class Options(object): cache[obj] = model # Collect also objects which are in relation to some proxy child/parent of self. proxy_cache = cache.copy() - for klass in get_models(include_auto_created=True, only_installed=False): + for klass in self.app_cache.get_models(include_auto_created=True, only_installed=False): if not klass._meta.swapped: for f in klass._meta.local_fields: if f.rel and not isinstance(f.rel.to, six.string_types) and f.generate_reverse_relation: @@ -538,7 +538,7 @@ class Options(object): cache[obj] = parent else: cache[obj] = model - for klass in get_models(only_installed=False): + for klass in self.app_cache.get_models(only_installed=False): if not klass._meta.swapped: for f in klass._meta.local_many_to_many: if (f.rel diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 33b870a335..2ff3f73b8a 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -116,7 +116,7 @@ class OperationTests(MigrationTestBase): """ project_state = self.set_up_test_model("test_adflmm", second_model=True) # Test the state alteration - operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable")) + operation = migrations.AddField("Pony", "stables", models.ManyToManyField("Stable", related_name="ponies")) new_state = project_state.clone() operation.state_forwards("test_adflmm", new_state) self.assertEqual(len(new_state.models["test_adflmm", "pony"].fields), 4) @@ -126,6 +126,13 @@ class OperationTests(MigrationTestBase): operation.database_forwards("test_adflmm", editor, project_state, new_state) self.assertTableExists("test_adflmm_pony_stables") self.assertColumnNotExists("test_adflmm_pony", "stables") + # Make sure the M2M field actually works + app_cache = new_state.render() + Pony = app_cache.get_model("test_adflmm", "Pony") + p = Pony.objects.create(pink=False, weight=4.55) + p.stables.create() + self.assertEqual(p.stables.count(), 1) + p.stables.all().delete() # And test reversal with connection.schema_editor() as editor: operation.database_backwards("test_adflmm", editor, new_state, project_state) diff --git a/tests/schema/models.py b/tests/schema/models.py index 69cf06f3c4..dc717ec105 100644 --- a/tests/schema/models.py +++ b/tests/schema/models.py @@ -37,7 +37,7 @@ class BookWithM2M(models.Model): author = models.ForeignKey(Author) title = models.CharField(max_length=100, db_index=True) pub_date = models.DateTimeField() - tags = models.ManyToManyField("Tag", related_name="books") + tags = models.ManyToManyField("TagM2MTest", related_name="books") class Meta: app_cache = new_app_cache @@ -62,6 +62,14 @@ class Tag(models.Model): app_cache = new_app_cache +class TagM2MTest(models.Model): + title = models.CharField(max_length=255) + slug = models.SlugField(unique=True) + + class Meta: + app_cache = new_app_cache + + class TagIndexed(models.Model): title = models.CharField(max_length=255) slug = models.SlugField(unique=True) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index d4e76e8567..bf9fa6bbcc 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -6,7 +6,7 @@ from django.db import connection, DatabaseError, IntegrityError from django.db.models.fields import IntegerField, TextField, CharField, SlugField from django.db.models.fields.related import ManyToManyField, ForeignKey from django.db.transaction import atomic -from .models import Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagUniqueRename, UniqueTest +from .models import Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest class SchemaTests(TransactionTestCase): @@ -20,7 +20,7 @@ class SchemaTests(TransactionTestCase): available_apps = [] - models = [Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagUniqueRename, UniqueTest] + models = [Author, AuthorWithM2M, Book, BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest] no_table_strings = ["no such table", "unknown table", "does not exist"] # Utility functions @@ -234,7 +234,7 @@ class SchemaTests(TransactionTestCase): editor.create_model(BookWithM2M) # Ensure there is now an m2m table there columns = self.column_classes(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through) - self.assertEqual(columns['tag_id'][0], "IntegerField") + self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField") def test_m2m(self): """ @@ -243,9 +243,9 @@ class SchemaTests(TransactionTestCase): # Create the tables with connection.schema_editor() as editor: editor.create_model(AuthorWithM2M) - editor.create_model(Tag) + editor.create_model(TagM2MTest) # Create an M2M field - new_field = ManyToManyField("schema.Tag", related_name="authors") + new_field = ManyToManyField("schema.TagM2MTest", related_name="authors") new_field.contribute_to_class(AuthorWithM2M, "tags") try: # Ensure there's no m2m table there @@ -258,7 +258,7 @@ class SchemaTests(TransactionTestCase): ) # Ensure there is now an m2m table there columns = self.column_classes(new_field.rel.through) - self.assertEqual(columns['tag_id'][0], "IntegerField") + self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField") # Remove the M2M table again with connection.schema_editor() as editor: editor.remove_field( @@ -279,17 +279,17 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.create_model(Author) editor.create_model(BookWithM2M) - editor.create_model(Tag) + editor.create_model(TagM2MTest) editor.create_model(UniqueTest) - # Ensure the M2M exists and points to Tag + # Ensure the M2M exists and points to TagM2MTest constraints = connection.introspection.get_constraints(connection.cursor(), BookWithM2M._meta.get_field_by_name("tags")[0].rel.through._meta.db_table) if connection.features.supports_foreign_keys: for name, details in constraints.items(): - if details['columns'] == ["tag_id"] and details['foreign_key']: - self.assertEqual(details['foreign_key'], ('schema_tag', 'id')) + if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']: + self.assertEqual(details['foreign_key'], ('schema_tagm2mtest', 'id')) break else: - self.fail("No FK constraint for tag_id found") + self.fail("No FK constraint for tagm2mtest_id found") # Repoint the M2M new_field = ManyToManyField(UniqueTest) new_field.contribute_to_class(BookWithM2M, "uniques") @@ -310,7 +310,7 @@ class SchemaTests(TransactionTestCase): self.assertEqual(details['foreign_key'], ('schema_uniquetest', 'id')) break else: - self.fail("No FK constraint for tag_id found") + self.fail("No FK constraint for uniquetest_id found") finally: # Cleanup model states BookWithM2M._meta.local_many_to_many.remove(new_field)