Fixed #22183: Through M2Ms now correctly handled
This commit is contained in:
parent
cdf6eba181
commit
6b07804474
|
@ -262,7 +262,8 @@ class BaseDatabaseSchemaEditor(object):
|
||||||
})
|
})
|
||||||
# Make M2M tables
|
# Make M2M tables
|
||||||
for field in model._meta.local_many_to_many:
|
for field in model._meta.local_many_to_many:
|
||||||
self.create_model(field.rel.through)
|
if field.rel.through._meta.auto_created:
|
||||||
|
self.create_model(field.rel.through)
|
||||||
|
|
||||||
def delete_model(self, model):
|
def delete_model(self, model):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -2032,6 +2032,11 @@ class ManyToManyField(RelatedField):
|
||||||
kwargs['to'] = self.rel.to
|
kwargs['to'] = self.rel.to
|
||||||
else:
|
else:
|
||||||
kwargs['to'] = "%s.%s" % (self.rel.to._meta.app_label, self.rel.to._meta.object_name)
|
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
|
# If swappable is True, then see if we're actually pointing to the target
|
||||||
# of a swap.
|
# of a swap.
|
||||||
swappable_setting = self.swappable_setting
|
swappable_setting = self.swappable_setting
|
||||||
|
|
|
@ -242,6 +242,12 @@ class FieldDeconstructionTests(TestCase):
|
||||||
self.assertEqual(args, [])
|
self.assertEqual(args, [])
|
||||||
self.assertEqual(kwargs, {"to": "auth.User"})
|
self.assertEqual(kwargs, {"to": "auth.User"})
|
||||||
self.assertEqual(kwargs['to'].setting_name, "AUTH_USER_MODEL")
|
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")
|
@override_settings(AUTH_USER_MODEL="auth.Permission")
|
||||||
def test_many_to_many_field_swapped(self):
|
def test_many_to_many_field_swapped(self):
|
||||||
|
|
|
@ -44,6 +44,21 @@ class BookWithM2M(models.Model):
|
||||||
apps = new_apps
|
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):
|
class BookWithSlug(models.Model):
|
||||||
author = models.ForeignKey(Author)
|
author = models.ForeignKey(Author)
|
||||||
title = models.CharField(max_length=100, db_index=True)
|
title = models.CharField(max_length=100, db_index=True)
|
||||||
|
|
|
@ -9,7 +9,7 @@ from django.db.models.fields.related import ManyToManyField, ForeignKey
|
||||||
from django.db.transaction import atomic
|
from django.db.transaction import atomic
|
||||||
from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
|
from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
|
||||||
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
|
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
|
||||||
UniqueTest, Thing)
|
UniqueTest, Thing, TagThrough, BookWithM2MThrough)
|
||||||
|
|
||||||
|
|
||||||
class SchemaTests(TransactionTestCase):
|
class SchemaTests(TransactionTestCase):
|
||||||
|
@ -26,7 +26,7 @@ class SchemaTests(TransactionTestCase):
|
||||||
models = [
|
models = [
|
||||||
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
|
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
|
||||||
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
|
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
|
||||||
Thing
|
Thing, TagThrough, BookWithM2MThrough
|
||||||
]
|
]
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
|
@ -310,6 +310,20 @@ class SchemaTests(TransactionTestCase):
|
||||||
columns = self.column_classes(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through)
|
columns = self.column_classes(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through)
|
||||||
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
|
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):
|
def test_m2m(self):
|
||||||
"""
|
"""
|
||||||
Tests adding/removing M2M fields on models
|
Tests adding/removing M2M fields on models
|
||||||
|
|
Loading…
Reference in New Issue