Kaydet (Commit) b25aee3b authored tarafından Andrew Godwin's avatar Andrew Godwin

Fixed #22476: Couldn't alter attributes on M2Ms with through= set

üst 5ea34f3f
......@@ -483,8 +483,11 @@ class BaseDatabaseSchemaEditor(object):
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):
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:
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,
new_field,
))
......
......@@ -148,8 +148,11 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
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):
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:
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,
new_field,
))
......
......@@ -24,6 +24,22 @@ class AuthorWithM2M(models.Model):
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):
author = models.ForeignKey(Author)
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 .models import (Author, AuthorWithM2M, Book, BookWithLongName,
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
UniqueTest, Thing, TagThrough, BookWithM2MThrough)
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough)
class SchemaTests(TransactionTestCase):
......@@ -402,6 +402,30 @@ class SchemaTests(TransactionTestCase):
# Cleanup model states
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):
"""
Tests repointing M2M fields
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment