[1.7.x] Fixed #22476: Couldn't alter attributes on M2Ms with through= set
This commit is contained in:
parent
bc82c0dbac
commit
f2bf59a5bc
|
@ -483,8 +483,11 @@ class BaseDatabaseSchemaEditor(object):
|
||||||
new_type = new_db_params['type']
|
new_type = new_db_params['type']
|
||||||
if old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and old_field.rel.through._meta.auto_created and new_field.rel.through._meta.auto_created):
|
if old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and old_field.rel.through._meta.auto_created and new_field.rel.through._meta.auto_created):
|
||||||
return self._alter_many_to_many(model, old_field, new_field, strict)
|
return self._alter_many_to_many(model, old_field, new_field, strict)
|
||||||
|
elif old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and not old_field.rel.through._meta.auto_created and not new_field.rel.through._meta.auto_created):
|
||||||
|
# Both sides have through models; this is a no-op.
|
||||||
|
return
|
||||||
elif old_type is None or new_type is None:
|
elif old_type is None or new_type is None:
|
||||||
raise ValueError("Cannot alter field %s into %s - they are not compatible types (probably means only one is an M2M with implicit through model)" % (
|
raise ValueError("Cannot alter field %s into %s - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)" % (
|
||||||
old_field,
|
old_field,
|
||||||
new_field,
|
new_field,
|
||||||
))
|
))
|
||||||
|
|
|
@ -148,8 +148,11 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
|
||||||
new_type = new_db_params['type']
|
new_type = new_db_params['type']
|
||||||
if old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and old_field.rel.through._meta.auto_created and new_field.rel.through._meta.auto_created):
|
if old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and old_field.rel.through._meta.auto_created and new_field.rel.through._meta.auto_created):
|
||||||
return self._alter_many_to_many(model, old_field, new_field, strict)
|
return self._alter_many_to_many(model, old_field, new_field, strict)
|
||||||
|
elif old_type is None and new_type is None and (old_field.rel.through and new_field.rel.through and not old_field.rel.through._meta.auto_created and not new_field.rel.through._meta.auto_created):
|
||||||
|
# Both sides have through models; this is a no-op.
|
||||||
|
return
|
||||||
elif old_type is None or new_type is None:
|
elif old_type is None or new_type is None:
|
||||||
raise ValueError("Cannot alter field %s into %s - they are not compatible types (probably means only one is an M2M with implicit through model)" % (
|
raise ValueError("Cannot alter field %s into %s - they are not compatible types (you cannot alter to or from M2M fields, or add or remove through= on M2M fields)" % (
|
||||||
old_field,
|
old_field,
|
||||||
new_field,
|
new_field,
|
||||||
))
|
))
|
||||||
|
|
|
@ -24,6 +24,22 @@ class AuthorWithM2M(models.Model):
|
||||||
apps = new_apps
|
apps = new_apps
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorWithM2MThrough(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
tags = models.ManyToManyField("schema.TagM2MTest", related_name="authors", through="AuthorTag")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
apps = new_apps
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorTag(models.Model):
|
||||||
|
author = models.ForeignKey("schema.AuthorWithM2MThrough")
|
||||||
|
tag = models.ForeignKey("schema.TagM2MTest")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
apps = new_apps
|
||||||
|
|
||||||
|
|
||||||
class Book(models.Model):
|
class Book(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, TagThrough, BookWithM2MThrough)
|
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough)
|
||||||
|
|
||||||
|
|
||||||
class SchemaTests(TransactionTestCase):
|
class SchemaTests(TransactionTestCase):
|
||||||
|
@ -402,6 +402,30 @@ class SchemaTests(TransactionTestCase):
|
||||||
# Cleanup model states
|
# Cleanup model states
|
||||||
AuthorWithM2M._meta.local_many_to_many.remove(new_field)
|
AuthorWithM2M._meta.local_many_to_many.remove(new_field)
|
||||||
|
|
||||||
|
def test_m2m_through_alter(self):
|
||||||
|
"""
|
||||||
|
Tests altering M2Ms with explicit through models (should no-op)
|
||||||
|
"""
|
||||||
|
# Create the tables
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
editor.create_model(AuthorTag)
|
||||||
|
editor.create_model(AuthorWithM2MThrough)
|
||||||
|
editor.create_model(TagM2MTest)
|
||||||
|
# Ensure the m2m table is there
|
||||||
|
self.assertEqual(len(self.column_classes(AuthorTag)), 3)
|
||||||
|
# "Alter" the field's blankness. This should not actually do anything.
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
old_field = AuthorWithM2MThrough._meta.get_field_by_name("tags")[0]
|
||||||
|
new_field = ManyToManyField("schema.TagM2MTest", related_name="authors", through="AuthorTag")
|
||||||
|
new_field.contribute_to_class(AuthorWithM2MThrough, "tags")
|
||||||
|
editor.alter_field(
|
||||||
|
Author,
|
||||||
|
old_field,
|
||||||
|
new_field,
|
||||||
|
)
|
||||||
|
# Ensure the m2m table is still there
|
||||||
|
self.assertEqual(len(self.column_classes(AuthorTag)), 3)
|
||||||
|
|
||||||
def test_m2m_repoint(self):
|
def test_m2m_repoint(self):
|
||||||
"""
|
"""
|
||||||
Tests repointing M2M fields
|
Tests repointing M2M fields
|
||||||
|
|
Loading…
Reference in New Issue