Add more stringent M2M tests and fix the bug they exposed

This commit is contained in:
Andrew Godwin 2013-08-19 13:50:26 +01:00
parent 5b522cd85a
commit 52edc16086
4 changed files with 32 additions and 17 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)