Add more stringent M2M tests and fix the bug they exposed
This commit is contained in:
parent
5b522cd85a
commit
52edc16086
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue