Commit 6b078044 authored by Andrew Godwin's avatar Andrew Godwin
Browse files

Fixed #22183: Through M2Ms now correctly handled

parent cdf6eba1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -262,6 +262,7 @@ class BaseDatabaseSchemaEditor(object):
            })
        # Make M2M tables
        for field in model._meta.local_many_to_many:
            if field.rel.through._meta.auto_created:
                self.create_model(field.rel.through)

    def delete_model(self, model):
+5 −0
Original line number Diff line number Diff line
@@ -2032,6 +2032,11 @@ class ManyToManyField(RelatedField):
            kwargs['to'] = self.rel.to
        else:
            kwargs['to'] = "%s.%s" % (self.rel.to._meta.app_label, self.rel.to._meta.object_name)
        if getattr(self.rel, 'through', None) is not None:
            if isinstance(self.rel.through, six.string_types):
                kwargs['through'] = self.rel.through
            else:
                kwargs['through'] = "%s.%s" % (self.rel.through._meta.app_label, self.rel.through._meta.object_name)
        # If swappable is True, then see if we're actually pointing to the target
        # of a swap.
        swappable_setting = self.swappable_setting
+6 −0
Original line number Diff line number Diff line
@@ -242,6 +242,12 @@ class FieldDeconstructionTests(TestCase):
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "auth.User"})
        self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
        # Test through
        field = models.ManyToManyField("auth.Permission", through="auth.Group")
        name, path, args, kwargs = field.deconstruct()
        self.assertEqual(path, "django.db.models.ManyToManyField")
        self.assertEqual(args, [])
        self.assertEqual(kwargs, {"to": "auth.Permission", "through": "auth.Group"})

    @override_settings(AUTH_USER_MODEL="auth.Permission")
    def test_many_to_many_field_swapped(self):
+15 −0
Original line number Diff line number Diff line
@@ -44,6 +44,21 @@ class BookWithM2M(models.Model):
        apps = new_apps


class TagThrough(models.Model):
    book = models.ForeignKey("schema.BookWithM2MThrough")
    tag = models.ForeignKey("schema.TagM2MTest")

    class Meta:
        apps = new_apps


class BookWithM2MThrough(models.Model):
    tags = models.ManyToManyField("TagM2MTest", related_name="books", through=TagThrough)

    class Meta:
        apps = new_apps


class BookWithSlug(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100, db_index=True)
+16 −2
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ from django.db.models.fields.related import ManyToManyField, ForeignKey
from django.db.transaction import atomic
from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
    BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
    UniqueTest, Thing)
    UniqueTest, Thing, TagThrough, BookWithM2MThrough)


class SchemaTests(TransactionTestCase):
@@ -26,7 +26,7 @@ class SchemaTests(TransactionTestCase):
    models = [
        Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
        BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
        Thing
        Thing, TagThrough, BookWithM2MThrough
    ]

    # Utility functions
@@ -310,6 +310,20 @@ class SchemaTests(TransactionTestCase):
        columns = self.column_classes(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through)
        self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")

    def test_m2m_create_through(self):
        """
        Tests M2M fields on models during creation with through models
        """
        # Create the tables
        with connection.schema_editor() as editor:
            editor.create_model(TagThrough)
            editor.create_model(TagM2MTest)
            editor.create_model(BookWithM2MThrough)
        # Ensure there is now an m2m table there
        columns = self.column_classes(TagThrough)
        self.assertEqual(columns['book_id'][0], "IntegerField")
        self.assertEqual(columns['tag_id'][0], "IntegerField")

    def test_m2m(self):
        """
        Tests adding/removing M2M fields on models