Cleaned up schema tests
Thanks Tim Graham for the review.
This commit is contained in:
parent
44ad691558
commit
0204714b0b
|
@ -52,3 +52,7 @@ class CustomManyToManyField(RelatedField):
|
|||
_get_m2m_attr = ManyToManyField.__dict__['_get_m2m_attr']
|
||||
_get_m2m_reverse_attr = ManyToManyField.__dict__['_get_m2m_reverse_attr']
|
||||
_get_m2m_db_table = ManyToManyField.__dict__['_get_m2m_db_table']
|
||||
|
||||
|
||||
class InheritedManyToManyField(ManyToManyField):
|
||||
pass
|
||||
|
|
|
@ -25,24 +25,9 @@ class AuthorWithDefaultHeight(models.Model):
|
|||
apps = new_apps
|
||||
|
||||
|
||||
class AuthorWithM2M(models.Model):
|
||||
class AuthorWithEvenLongerName(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
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")
|
||||
height = models.PositiveIntegerField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
@ -67,6 +52,13 @@ class BookWeak(models.Model):
|
|||
apps = new_apps
|
||||
|
||||
|
||||
class BookWithLongName(models.Model):
|
||||
author_foreign_key_with_really_long_field_name = models.ForeignKey(AuthorWithEvenLongerName)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
|
||||
class BookWithO2O(models.Model):
|
||||
author = models.OneToOneField(Author)
|
||||
title = models.CharField(max_length=100, db_index=True)
|
||||
|
@ -77,31 +69,6 @@ class BookWithO2O(models.Model):
|
|||
db_table = "schema_book"
|
||||
|
||||
|
||||
class BookWithM2M(models.Model):
|
||||
author = models.ForeignKey(Author)
|
||||
title = models.CharField(max_length=100, db_index=True)
|
||||
pub_date = models.DateTimeField()
|
||||
tags = models.ManyToManyField("TagM2MTest", related_name="books")
|
||||
|
||||
class Meta:
|
||||
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)
|
||||
|
@ -113,6 +80,10 @@ class BookWithSlug(models.Model):
|
|||
db_table = "schema_book"
|
||||
|
||||
|
||||
class Note(models.Model):
|
||||
info = models.TextField()
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
slug = models.SlugField(unique=True)
|
||||
|
@ -121,14 +92,6 @@ class Tag(models.Model):
|
|||
apps = new_apps
|
||||
|
||||
|
||||
class TagM2MTest(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
slug = models.SlugField(unique=True)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
|
||||
class TagIndexed(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
slug = models.SlugField(unique=True)
|
||||
|
@ -138,6 +101,14 @@ class TagIndexed(models.Model):
|
|||
index_together = [["slug", "title"]]
|
||||
|
||||
|
||||
class TagM2MTest(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
slug = models.SlugField(unique=True)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
|
||||
class TagUniqueRename(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
slug2 = models.SlugField(unique=True)
|
||||
|
@ -147,30 +118,6 @@ class TagUniqueRename(models.Model):
|
|||
db_table = "schema_tag"
|
||||
|
||||
|
||||
class UniqueTest(models.Model):
|
||||
year = models.IntegerField()
|
||||
slug = models.SlugField(unique=False)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
unique_together = ["year", "slug"]
|
||||
|
||||
|
||||
class AuthorWithEvenLongerName(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
height = models.PositiveIntegerField(null=True, blank=True)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
|
||||
class BookWithLongName(models.Model):
|
||||
author_foreign_key_with_really_long_field_name = models.ForeignKey(AuthorWithEvenLongerName)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
|
||||
# Based on tests/reserved_names/models.py
|
||||
@python_2_unicode_compatible
|
||||
class Thing(models.Model):
|
||||
|
@ -183,5 +130,10 @@ class Thing(models.Model):
|
|||
return self.when
|
||||
|
||||
|
||||
class Note(models.Model):
|
||||
info = models.TextField()
|
||||
class UniqueTest(models.Model):
|
||||
year = models.IntegerField()
|
||||
slug = models.SlugField(unique=False)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
unique_together = ["year", "slug"]
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
import datetime
|
||||
import itertools
|
||||
import unittest
|
||||
|
||||
from django.test import TransactionTestCase
|
||||
from django.db import connection, DatabaseError, IntegrityError, OperationalError
|
||||
from django.db.models.fields import (BinaryField, BooleanField, CharField, IntegerField,
|
||||
PositiveIntegerField, SlugField, TextField)
|
||||
from django.db.models import Model
|
||||
from django.db.models.fields import (BinaryField, BooleanField, CharField, DateTimeField,
|
||||
IntegerField, PositiveIntegerField, SlugField, TextField)
|
||||
from django.db.models.fields.related import ForeignKey, ManyToManyField, OneToOneField
|
||||
from django.db.transaction import atomic
|
||||
from .fields import CustomManyToManyField
|
||||
from .models import (Author, AuthorWithDefaultHeight, AuthorWithM2M, Book, BookWithLongName,
|
||||
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
|
||||
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough,
|
||||
AuthorWithEvenLongerName, BookWeak, Note, BookWithO2O)
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from .fields import CustomManyToManyField, InheritedManyToManyField
|
||||
from .models import (
|
||||
Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book, BookWeak,
|
||||
BookWithLongName, BookWithO2O, BookWithSlug, Note, Tag, TagIndexed,
|
||||
TagM2MTest, TagUniqueRename, Thing, UniqueTest, new_apps
|
||||
)
|
||||
|
||||
|
||||
class SchemaTests(TransactionTestCase):
|
||||
|
@ -26,24 +30,34 @@ class SchemaTests(TransactionTestCase):
|
|||
available_apps = []
|
||||
|
||||
models = [
|
||||
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
|
||||
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
|
||||
Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName,
|
||||
BookWeak, BookWithO2O,
|
||||
Author, AuthorWithDefaultHeight, AuthorWithEvenLongerName, Book,
|
||||
BookWeak, BookWithLongName, BookWithO2O, BookWithSlug, Note, Tag,
|
||||
TagIndexed, TagM2MTest, TagUniqueRename, Thing, UniqueTest,
|
||||
]
|
||||
|
||||
# Utility functions
|
||||
|
||||
def setUp(self):
|
||||
# local_models should contain test dependent model classes that will be
|
||||
# automatically removed from the app cache on test tear down.
|
||||
self.local_models = []
|
||||
|
||||
def tearDown(self):
|
||||
# Delete any tables made for our models
|
||||
self.delete_tables()
|
||||
new_apps.clear_cache()
|
||||
for model in new_apps.get_models():
|
||||
model._meta._expire_cache()
|
||||
if 'schema' in new_apps.all_models:
|
||||
for model in self.local_models:
|
||||
del new_apps.all_models['schema'][model._meta.model_name]
|
||||
|
||||
def delete_tables(self):
|
||||
"Deletes all model tables for our models for a clean test environment"
|
||||
with connection.cursor() as cursor:
|
||||
connection.disable_constraint_checking()
|
||||
table_names = connection.introspection.table_names(cursor)
|
||||
for model in self.models:
|
||||
for model in itertools.chain(SchemaTests.models, self.local_models):
|
||||
# Remove any M2M tables first
|
||||
for field in model._meta.local_many_to_many:
|
||||
with atomic():
|
||||
|
@ -134,15 +148,11 @@ class SchemaTests(TransactionTestCase):
|
|||
pub_date=datetime.datetime.now(),
|
||||
)
|
||||
# Repoint the FK constraint
|
||||
old_field = Book._meta.get_field("author")
|
||||
new_field = ForeignKey(Tag)
|
||||
new_field.set_attributes_from_name("author")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Book,
|
||||
Book._meta.get_field("author"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Book, old_field, new_field, strict=True)
|
||||
# Make sure the new FK constraint is present
|
||||
constraints = self.get_constraints(Book._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
|
@ -173,25 +183,17 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = ForeignKey(Tag, db_constraint=False)
|
||||
new_field.set_attributes_from_name("tag")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Make sure no FK constraint is present
|
||||
constraints = self.get_constraints(Author._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["tag_id"] and details['foreign_key']:
|
||||
self.fail("FK constraint for tag_id found")
|
||||
# Alter to one with a constraint
|
||||
new_field_2 = ForeignKey(Tag)
|
||||
new_field_2.set_attributes_from_name("tag")
|
||||
new_field2 = ForeignKey(Tag)
|
||||
new_field2.set_attributes_from_name("tag")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
new_field,
|
||||
new_field_2,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, new_field, new_field2, strict=True)
|
||||
# Make sure the new FK constraint is present
|
||||
constraints = self.get_constraints(Author._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
|
@ -201,45 +203,56 @@ class SchemaTests(TransactionTestCase):
|
|||
else:
|
||||
self.fail("No FK constraint for tag_id found")
|
||||
# Alter to one without a constraint again
|
||||
new_field_2 = ForeignKey(Tag)
|
||||
new_field_2.set_attributes_from_name("tag")
|
||||
new_field2 = ForeignKey(Tag)
|
||||
new_field2.set_attributes_from_name("tag")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
new_field_2,
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, new_field2, new_field, strict=True)
|
||||
# Make sure no FK constraint is present
|
||||
constraints = self.get_constraints(Author._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["tag_id"] and details['foreign_key']:
|
||||
self.fail("FK constraint for tag_id found")
|
||||
|
||||
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
|
||||
def test_m2m_db_constraint(self):
|
||||
def _test_m2m_db_constraint(self, M2MFieldClass):
|
||||
class LocalAuthorWithM2M(Model):
|
||||
name = CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalAuthorWithM2M]
|
||||
|
||||
# Create the table
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(Tag)
|
||||
editor.create_model(Author)
|
||||
editor.create_model(LocalAuthorWithM2M)
|
||||
# Check that initial tables are there
|
||||
list(Author.objects.all())
|
||||
list(LocalAuthorWithM2M.objects.all())
|
||||
list(Tag.objects.all())
|
||||
# Make a db_constraint=False FK
|
||||
new_field = ManyToManyField("schema.Tag", related_name="authors", db_constraint=False)
|
||||
new_field.contribute_to_class(Author, "tags")
|
||||
new_field = M2MFieldClass(Tag, related_name="authors", db_constraint=False)
|
||||
new_field.contribute_to_class(LocalAuthorWithM2M, "tags")
|
||||
# Add the field
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(LocalAuthorWithM2M, new_field)
|
||||
# Make sure no FK constraint is present
|
||||
constraints = self.get_constraints(new_field.rel.through._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["tag_id"] and details['foreign_key']:
|
||||
self.fail("FK constraint for tag_id found")
|
||||
|
||||
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
|
||||
def test_m2m_db_constraint(self):
|
||||
self._test_m2m_db_constraint(ManyToManyField)
|
||||
|
||||
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
|
||||
def test_m2m_db_constraint_custom(self):
|
||||
self._test_m2m_db_constraint(CustomManyToManyField)
|
||||
|
||||
@unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
|
||||
def test_m2m_db_constraint_inherited(self):
|
||||
self._test_m2m_db_constraint(InheritedManyToManyField)
|
||||
|
||||
def test_add_field(self):
|
||||
"""
|
||||
Tests adding fields to models
|
||||
|
@ -254,10 +267,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = IntegerField(null=True)
|
||||
new_field.set_attributes_from_name("age")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['age'][0], "IntegerField")
|
||||
|
@ -280,10 +290,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = CharField(max_length=30, default="Godwin")
|
||||
new_field.set_attributes_from_name("surname")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['surname'][0], "CharField")
|
||||
|
@ -308,10 +315,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = BooleanField(default=False)
|
||||
new_field.set_attributes_from_name("awesome")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
# BooleanField are stored as TINYINT(1) on MySQL.
|
||||
|
@ -345,10 +349,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = TestTransformField(default={1: 2})
|
||||
new_field.set_attributes_from_name("thing")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Ensure the field is there
|
||||
columns = self.column_classes(Author)
|
||||
field_type, field_info = columns['thing']
|
||||
|
@ -367,10 +368,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = BinaryField(blank=True)
|
||||
new_field.set_attributes_from_name("bits")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(Author, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
# MySQL annoyingly uses the same backend, so it'll come back as one of
|
||||
|
@ -389,15 +387,11 @@ class SchemaTests(TransactionTestCase):
|
|||
self.assertEqual(columns['name'][0], "CharField")
|
||||
self.assertEqual(bool(columns['name'][1][6]), bool(connection.features.interprets_empty_strings_as_nulls))
|
||||
# Alter the name field to a TextField
|
||||
old_field = Author._meta.get_field("name")
|
||||
new_field = TextField(null=True)
|
||||
new_field.set_attributes_from_name("name")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
Author._meta.get_field("name"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, old_field, new_field, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['name'][0], "TextField")
|
||||
|
@ -406,12 +400,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field2 = TextField(null=False)
|
||||
new_field2.set_attributes_from_name("name")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
new_field,
|
||||
new_field2,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, new_field, new_field2, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['name'][0], "TextField")
|
||||
|
@ -420,15 +409,14 @@ class SchemaTests(TransactionTestCase):
|
|||
def test_alter_text_field(self):
|
||||
# Regression for "BLOB/TEXT column 'info' can't have a default value")
|
||||
# on MySQL.
|
||||
# Create the table
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(Note)
|
||||
old_field = Note._meta.get_field("info")
|
||||
new_field = TextField(blank=True)
|
||||
new_field.set_attributes_from_name("info")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Note,
|
||||
Note._meta.get_field("info"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Note, old_field, new_field, strict=True)
|
||||
|
||||
def test_alter_null_to_not_null(self):
|
||||
"""
|
||||
|
@ -447,14 +435,11 @@ class SchemaTests(TransactionTestCase):
|
|||
self.assertEqual(Author.objects.get(name='Not null author').height, 12)
|
||||
self.assertIsNone(Author.objects.get(name='Null author').height)
|
||||
# Alter the height field to NOT NULL with default
|
||||
old_field = Author._meta.get_field("height")
|
||||
new_field = PositiveIntegerField(default=42)
|
||||
new_field.set_attributes_from_name("height")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
Author._meta.get_field("height"),
|
||||
new_field
|
||||
)
|
||||
editor.alter_field(Author, old_field, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertFalse(columns['height'][1][6])
|
||||
|
@ -475,14 +460,11 @@ class SchemaTests(TransactionTestCase):
|
|||
columns = self.column_classes(AuthorWithDefaultHeight)
|
||||
self.assertTrue(columns['height'][1][6])
|
||||
# Alter the height field to NOT NULL keeping the previous default
|
||||
old_field = AuthorWithDefaultHeight._meta.get_field("height")
|
||||
new_field = PositiveIntegerField(default=42)
|
||||
new_field.set_attributes_from_name("height")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
AuthorWithDefaultHeight,
|
||||
AuthorWithDefaultHeight._meta.get_field("height"),
|
||||
new_field,
|
||||
)
|
||||
editor.alter_field(AuthorWithDefaultHeight, old_field, new_field)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(AuthorWithDefaultHeight)
|
||||
self.assertFalse(columns['height'][1][6])
|
||||
|
@ -508,15 +490,11 @@ class SchemaTests(TransactionTestCase):
|
|||
else:
|
||||
self.fail("No FK constraint for author_id found")
|
||||
# Alter the FK
|
||||
old_field = Book._meta.get_field("author")
|
||||
new_field = ForeignKey(Author, editable=False)
|
||||
new_field.set_attributes_from_name("author")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Book,
|
||||
Book._meta.get_field("author"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Book, old_field, new_field, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Book)
|
||||
self.assertEqual(columns['author_id'][0], "IntegerField")
|
||||
|
@ -556,15 +534,11 @@ class SchemaTests(TransactionTestCase):
|
|||
author_is_fk = True
|
||||
self.assertTrue(author_is_fk, "No FK constraint for author_id found")
|
||||
# Alter the OneToOneField to ForeignKey
|
||||
old_field = BookWithO2O._meta.get_field("author")
|
||||
new_field = ForeignKey(Author)
|
||||
new_field.set_attributes_from_name("author")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
BookWithO2O,
|
||||
BookWithO2O._meta.get_field("author"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(BookWithO2O, old_field, new_field, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Book)
|
||||
self.assertEqual(columns['author_id'][0], "IntegerField")
|
||||
|
@ -606,15 +580,11 @@ class SchemaTests(TransactionTestCase):
|
|||
author_is_fk = True
|
||||
self.assertTrue(author_is_fk, "No FK constraint for author_id found")
|
||||
# Alter the ForeignKey to OneToOneField
|
||||
old_field = Book._meta.get_field("author")
|
||||
new_field = OneToOneField(Author)
|
||||
new_field.set_attributes_from_name("author")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Book,
|
||||
Book._meta.get_field("author"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Book, old_field, new_field, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(BookWithO2O)
|
||||
self.assertEqual(columns['author_id'][0], "IntegerField")
|
||||
|
@ -639,17 +609,12 @@ class SchemaTests(TransactionTestCase):
|
|||
with connection.schema_editor() as editor:
|
||||
editor.create_model(Author)
|
||||
|
||||
old_field = Author._meta.get_field("id")
|
||||
new_field = IntegerField(primary_key=True)
|
||||
new_field.set_attributes_from_name("id")
|
||||
new_field.model = Author
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
Author._meta.get_field("id"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
|
||||
editor.alter_field(Author, old_field, new_field, strict=True)
|
||||
# This will fail if DROP DEFAULT is inadvertently executed on this
|
||||
# field which drops the id sequence, at least on PostgreSQL.
|
||||
Author.objects.create(name='Foo')
|
||||
|
@ -666,127 +631,202 @@ class SchemaTests(TransactionTestCase):
|
|||
self.assertEqual(columns['name'][0], "CharField")
|
||||
self.assertNotIn("display_name", columns)
|
||||
# Alter the name field's name
|
||||
old_field = Author._meta.get_field("name")
|
||||
new_field = CharField(max_length=254)
|
||||
new_field.set_attributes_from_name("display_name")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
Author._meta.get_field("name"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, old_field, new_field, strict=True)
|
||||
# Ensure the field is right afterwards
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['display_name'][0], "CharField")
|
||||
self.assertNotIn("name", columns)
|
||||
|
||||
def test_m2m_create(self):
|
||||
def _test_m2m_create(self, M2MFieldClass):
|
||||
"""
|
||||
Tests M2M fields on models during creation
|
||||
"""
|
||||
class LocalBookWithM2M(Model):
|
||||
author = ForeignKey(Author)
|
||||
title = CharField(max_length=100, db_index=True)
|
||||
pub_date = DateTimeField()
|
||||
tags = M2MFieldClass("TagM2MTest", related_name="books")
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalBookWithM2M]
|
||||
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(Author)
|
||||
editor.create_model(TagM2MTest)
|
||||
editor.create_model(BookWithM2M)
|
||||
editor.create_model(LocalBookWithM2M)
|
||||
# Ensure there is now an m2m table there
|
||||
columns = self.column_classes(BookWithM2M._meta.get_field("tags").rel.through)
|
||||
columns = self.column_classes(LocalBookWithM2M._meta.get_field("tags").rel.through)
|
||||
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
|
||||
|
||||
def test_m2m_create_through(self):
|
||||
def test_m2m_create(self):
|
||||
self._test_m2m_create(ManyToManyField)
|
||||
|
||||
def test_m2m_create_custom(self):
|
||||
self._test_m2m_create(CustomManyToManyField)
|
||||
|
||||
def test_m2m_create_inherited(self):
|
||||
self._test_m2m_create(InheritedManyToManyField)
|
||||
|
||||
def _test_m2m_create_through(self, M2MFieldClass):
|
||||
"""
|
||||
Tests M2M fields on models during creation with through models
|
||||
"""
|
||||
class LocalTagThrough(Model):
|
||||
book = ForeignKey("schema.LocalBookWithM2MThrough")
|
||||
tag = ForeignKey("schema.TagM2MTest")
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
class LocalBookWithM2MThrough(Model):
|
||||
tags = M2MFieldClass("TagM2MTest", related_name="books", through=LocalTagThrough)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalTagThrough, LocalBookWithM2MThrough]
|
||||
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(TagThrough)
|
||||
editor.create_model(LocalTagThrough)
|
||||
editor.create_model(TagM2MTest)
|
||||
editor.create_model(BookWithM2MThrough)
|
||||
editor.create_model(LocalBookWithM2MThrough)
|
||||
# Ensure there is now an m2m table there
|
||||
columns = self.column_classes(TagThrough)
|
||||
columns = self.column_classes(LocalTagThrough)
|
||||
self.assertEqual(columns['book_id'][0], "IntegerField")
|
||||
self.assertEqual(columns['tag_id'][0], "IntegerField")
|
||||
|
||||
def test_m2m(self):
|
||||
def test_m2m_create_through(self):
|
||||
self._test_m2m_create_through(ManyToManyField)
|
||||
|
||||
def test_m2m_create_through_custom(self):
|
||||
self._test_m2m_create_through(CustomManyToManyField)
|
||||
|
||||
def test_m2m_create_through_inherited(self):
|
||||
self._test_m2m_create_through(InheritedManyToManyField)
|
||||
|
||||
def _test_m2m(self, M2MFieldClass):
|
||||
"""
|
||||
Tests adding/removing M2M fields on models
|
||||
"""
|
||||
class LocalAuthorWithM2M(Model):
|
||||
name = CharField(max_length=255)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalAuthorWithM2M]
|
||||
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(AuthorWithM2M)
|
||||
editor.create_model(LocalAuthorWithM2M)
|
||||
editor.create_model(TagM2MTest)
|
||||
# Create an M2M field
|
||||
new_field = ManyToManyField("schema.TagM2MTest", related_name="authors")
|
||||
new_field.contribute_to_class(AuthorWithM2M, "tags")
|
||||
try:
|
||||
new_field = M2MFieldClass("schema.TagM2MTest", related_name="authors")
|
||||
new_field.contribute_to_class(LocalAuthorWithM2M, "tags")
|
||||
# Ensure there's no m2m table there
|
||||
self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
|
||||
# Add the field
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(LocalAuthorWithM2M, new_field)
|
||||
# Ensure there is now an m2m table there
|
||||
columns = self.column_classes(new_field.rel.through)
|
||||
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
|
||||
|
||||
# "Alter" the field. This should not rename the DB table to itself.
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
new_field,
|
||||
new_field,
|
||||
)
|
||||
editor.alter_field(LocalAuthorWithM2M, new_field, new_field)
|
||||
|
||||
# Remove the M2M table again
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_field(
|
||||
Author,
|
||||
new_field,
|
||||
)
|
||||
editor.remove_field(LocalAuthorWithM2M, new_field)
|
||||
# Ensure there's no m2m table there
|
||||
self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
|
||||
finally:
|
||||
# Cleanup model states
|
||||
AuthorWithM2M._meta.local_many_to_many.remove(new_field)
|
||||
|
||||
def test_m2m_through_alter(self):
|
||||
def test_m2m(self):
|
||||
self._test_m2m(ManyToManyField)
|
||||
|
||||
def test_m2m_custom(self):
|
||||
self._test_m2m(CustomManyToManyField)
|
||||
|
||||
def test_m2m_inherited(self):
|
||||
self._test_m2m(InheritedManyToManyField)
|
||||
|
||||
def _test_m2m_through_alter(self, M2MFieldClass):
|
||||
"""
|
||||
Tests altering M2Ms with explicit through models (should no-op)
|
||||
"""
|
||||
class LocalAuthorTag(Model):
|
||||
author = ForeignKey("schema.LocalAuthorWithM2MThrough")
|
||||
tag = ForeignKey("schema.TagM2MTest")
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
class LocalAuthorWithM2MThrough(Model):
|
||||
name = CharField(max_length=255)
|
||||
tags = M2MFieldClass("schema.TagM2MTest", related_name="authors", through=LocalAuthorTag)
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalAuthorTag, LocalAuthorWithM2MThrough]
|
||||
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(AuthorTag)
|
||||
editor.create_model(AuthorWithM2MThrough)
|
||||
editor.create_model(LocalAuthorTag)
|
||||
editor.create_model(LocalAuthorWithM2MThrough)
|
||||
editor.create_model(TagM2MTest)
|
||||
# Ensure the m2m table is there
|
||||
self.assertEqual(len(self.column_classes(AuthorTag)), 3)
|
||||
self.assertEqual(len(self.column_classes(LocalAuthorTag)), 3)
|
||||
# "Alter" the field's blankness. This should not actually do anything.
|
||||
old_field = LocalAuthorWithM2MThrough._meta.get_field("tags")
|
||||
new_field = M2MFieldClass("schema.TagM2MTest", related_name="authors", through=LocalAuthorTag)
|
||||
new_field.contribute_to_class(LocalAuthorWithM2MThrough, "tags")
|
||||
with connection.schema_editor() as editor:
|
||||
old_field = AuthorWithM2MThrough._meta.get_field("tags")
|
||||
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,
|
||||
)
|
||||
editor.alter_field(LocalAuthorWithM2MThrough, old_field, new_field)
|
||||
# Ensure the m2m table is still there
|
||||
self.assertEqual(len(self.column_classes(AuthorTag)), 3)
|
||||
self.assertEqual(len(self.column_classes(LocalAuthorTag)), 3)
|
||||
|
||||
def test_m2m_repoint(self):
|
||||
def test_m2m_through_alter(self):
|
||||
self._test_m2m_through_alter(ManyToManyField)
|
||||
|
||||
def test_m2m_through_alter_custom(self):
|
||||
self._test_m2m_through_alter(CustomManyToManyField)
|
||||
|
||||
def test_m2m_through_alter_inherited(self):
|
||||
self._test_m2m_through_alter(InheritedManyToManyField)
|
||||
|
||||
def _test_m2m_repoint(self, M2MFieldClass):
|
||||
"""
|
||||
Tests repointing M2M fields
|
||||
"""
|
||||
class LocalBookWithM2M(Model):
|
||||
author = ForeignKey(Author)
|
||||
title = CharField(max_length=100, db_index=True)
|
||||
pub_date = DateTimeField()
|
||||
tags = M2MFieldClass("TagM2MTest", related_name="books")
|
||||
|
||||
class Meta:
|
||||
apps = new_apps
|
||||
|
||||
self.local_models = [LocalBookWithM2M]
|
||||
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(Author)
|
||||
editor.create_model(BookWithM2M)
|
||||
editor.create_model(LocalBookWithM2M)
|
||||
editor.create_model(TagM2MTest)
|
||||
editor.create_model(UniqueTest)
|
||||
# Ensure the M2M exists and points to TagM2MTest
|
||||
constraints = self.get_constraints(BookWithM2M._meta.get_field("tags").rel.through._meta.db_table)
|
||||
constraints = self.get_constraints(LocalBookWithM2M._meta.get_field("tags").rel.through._meta.db_table)
|
||||
if connection.features.supports_foreign_keys:
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']:
|
||||
|
@ -795,17 +835,13 @@ class SchemaTests(TransactionTestCase):
|
|||
else:
|
||||
self.fail("No FK constraint for tagm2mtest_id found")
|
||||
# Repoint the M2M
|
||||
new_field = ManyToManyField(UniqueTest)
|
||||
new_field.contribute_to_class(BookWithM2M, "uniques")
|
||||
try:
|
||||
old_field = LocalBookWithM2M._meta.get_field("tags")
|
||||
new_field = M2MFieldClass(UniqueTest)
|
||||
new_field.contribute_to_class(LocalBookWithM2M, "uniques")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
BookWithM2M._meta.get_field("tags"),
|
||||
new_field,
|
||||
)
|
||||
editor.alter_field(LocalBookWithM2M, old_field, new_field)
|
||||
# Ensure old M2M is gone
|
||||
self.assertRaises(DatabaseError, self.column_classes, BookWithM2M._meta.get_field("tags").rel.through)
|
||||
self.assertRaises(DatabaseError, self.column_classes, LocalBookWithM2M._meta.get_field("tags").rel.through)
|
||||
# Ensure the new M2M exists and points to UniqueTest
|
||||
constraints = self.get_constraints(new_field.rel.through._meta.db_table)
|
||||
if connection.features.supports_foreign_keys:
|
||||
|
@ -815,13 +851,15 @@ class SchemaTests(TransactionTestCase):
|
|||
break
|
||||
else:
|
||||
self.fail("No FK constraint for uniquetest_id found")
|
||||
finally:
|
||||
# Cleanup through table separately
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_field(BookWithM2M, BookWithM2M._meta.get_field("uniques"))
|
||||
# Cleanup model states
|
||||
BookWithM2M._meta.local_many_to_many.remove(new_field)
|
||||
BookWithM2M._meta._expire_cache()
|
||||
|
||||
def test_m2m_repoint(self):
|
||||
self._test_m2m_repoint(ManyToManyField)
|
||||
|
||||
def test_m2m_repoint_custom(self):
|
||||
self._test_m2m_repoint(CustomManyToManyField)
|
||||
|
||||
def test_m2m_repoint_inherited(self):
|
||||
self._test_m2m_repoint(InheritedManyToManyField)
|
||||
|
||||
@unittest.skipUnless(connection.features.supports_column_check_constraints, "No check constraints")
|
||||
def test_check_constraints(self):
|
||||
|
@ -839,27 +877,19 @@ class SchemaTests(TransactionTestCase):
|
|||
else:
|
||||
self.fail("No check constraint for height found")
|
||||
# Alter the column to remove it
|
||||
old_field = Author._meta.get_field("height")
|
||||
new_field = IntegerField(null=True, blank=True)
|
||||
new_field.set_attributes_from_name("height")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
Author._meta.get_field("height"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, old_field, new_field, strict=True)
|
||||
constraints = self.get_constraints(Author._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["height"] and details['check']:
|
||||
self.fail("Check constraint for height found")
|
||||
# Alter the column to re-add it
|
||||
new_field2 = Author._meta.get_field("height")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Author,
|
||||
new_field,
|
||||
Author._meta.get_field("height"),
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Author, new_field, new_field2, strict=True)
|
||||
constraints = self.get_constraints(Author._meta.db_table)
|
||||
for name, details in constraints.items():
|
||||
if details['columns'] == ["height"] and details['check']:
|
||||
|
@ -879,43 +909,29 @@ class SchemaTests(TransactionTestCase):
|
|||
self.assertRaises(IntegrityError, Tag.objects.create, title="bar", slug="foo")
|
||||
Tag.objects.all().delete()
|
||||
# Alter the slug field to be non-unique
|
||||
old_field = Tag._meta.get_field("slug")
|
||||
new_field = SlugField(unique=False)
|
||||
new_field.set_attributes_from_name("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Tag,
|
||||
Tag._meta.get_field("slug"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Tag, old_field, new_field, strict=True)
|
||||
# Ensure the field is no longer unique
|
||||
Tag.objects.create(title="foo", slug="foo")
|
||||
Tag.objects.create(title="bar", slug="foo")
|
||||
Tag.objects.all().delete()
|
||||
# Alter the slug field to be unique
|
||||
new_new_field = SlugField(unique=True)
|
||||
new_new_field.set_attributes_from_name("slug")
|
||||
new_field2 = SlugField(unique=True)
|
||||
new_field2.set_attributes_from_name("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Tag,
|
||||
new_field,
|
||||
new_new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Tag, new_field, new_field2, strict=True)
|
||||
# Ensure the field is unique again
|
||||
Tag.objects.create(title="foo", slug="foo")
|
||||
self.assertRaises(IntegrityError, Tag.objects.create, title="bar", slug="foo")
|
||||
Tag.objects.all().delete()
|
||||
# Rename the field
|
||||
new_field = SlugField(unique=False)
|
||||
new_field.set_attributes_from_name("slug2")
|
||||
new_field3 = SlugField(unique=True)
|
||||
new_field3.set_attributes_from_name("slug2")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Tag,
|
||||
Tag._meta.get_field("slug"),
|
||||
TagUniqueRename._meta.get_field("slug2"),
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Tag, new_field2, new_field3, strict=True)
|
||||
# Ensure the field is still unique
|
||||
TagUniqueRename.objects.create(title="foo", slug2="foo")
|
||||
self.assertRaises(IntegrityError, TagUniqueRename.objects.create, title="bar", slug2="foo")
|
||||
|
@ -936,24 +952,16 @@ class SchemaTests(TransactionTestCase):
|
|||
UniqueTest.objects.all().delete()
|
||||
# Alter the model to its non-unique-together companion
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_unique_together(
|
||||
UniqueTest,
|
||||
UniqueTest._meta.unique_together,
|
||||
[],
|
||||
)
|
||||
editor.alter_unique_together(UniqueTest, UniqueTest._meta.unique_together, [])
|
||||
# Ensure the fields are no longer unique
|
||||
UniqueTest.objects.create(year=2012, slug="foo")
|
||||
UniqueTest.objects.create(year=2012, slug="foo")
|
||||
UniqueTest.objects.all().delete()
|
||||
# Alter it back
|
||||
new_new_field = SlugField(unique=True)
|
||||
new_new_field.set_attributes_from_name("slug")
|
||||
new_field2 = SlugField(unique=True)
|
||||
new_field2.set_attributes_from_name("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_unique_together(
|
||||
UniqueTest,
|
||||
[],
|
||||
UniqueTest._meta.unique_together,
|
||||
)
|
||||
editor.alter_unique_together(UniqueTest, [], UniqueTest._meta.unique_together)
|
||||
# Ensure the fields are unique again
|
||||
UniqueTest.objects.create(year=2012, slug="foo")
|
||||
self.assertRaises(IntegrityError, UniqueTest.objects.create, year=2012, slug="foo")
|
||||
|
@ -977,11 +985,7 @@ class SchemaTests(TransactionTestCase):
|
|||
)
|
||||
# Alter the model to add an index
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_index_together(
|
||||
Tag,
|
||||
[],
|
||||
[("slug", "title")],
|
||||
)
|
||||
editor.alter_index_together(Tag, [], [("slug", "title")])
|
||||
# Ensure there is now an index
|
||||
self.assertEqual(
|
||||
True,
|
||||
|
@ -992,14 +996,10 @@ class SchemaTests(TransactionTestCase):
|
|||
),
|
||||
)
|
||||
# Alter it back
|
||||
new_new_field = SlugField(unique=True)
|
||||
new_new_field.set_attributes_from_name("slug")
|
||||
new_field2 = SlugField(unique=True)
|
||||
new_field2.set_attributes_from_name("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_index_together(
|
||||
Tag,
|
||||
[("slug", "title")],
|
||||
[],
|
||||
)
|
||||
editor.alter_index_together(Tag, [("slug", "title")], [])
|
||||
# Ensure there's no index
|
||||
self.assertEqual(
|
||||
False,
|
||||
|
@ -1039,22 +1039,14 @@ class SchemaTests(TransactionTestCase):
|
|||
self.assertEqual(columns['name'][0], "CharField")
|
||||
# Alter the table
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_db_table(
|
||||
Author,
|
||||
"schema_author",
|
||||
"schema_otherauthor",
|
||||
)
|
||||
editor.alter_db_table(Author, "schema_author", "schema_otherauthor")
|
||||
# Ensure the table is there afterwards
|
||||
Author._meta.db_table = "schema_otherauthor"
|
||||
columns = self.column_classes(Author)
|
||||
self.assertEqual(columns['name'][0], "CharField")
|
||||
# Alter the table again
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_db_table(
|
||||
Author,
|
||||
"schema_otherauthor",
|
||||
"schema_author",
|
||||
)
|
||||
editor.alter_db_table(Author, "schema_otherauthor", "schema_author")
|
||||
# Ensure the table is still there
|
||||
Author._meta.db_table = "schema_author"
|
||||
columns = self.column_classes(Author)
|
||||
|
@ -1074,53 +1066,38 @@ class SchemaTests(TransactionTestCase):
|
|||
self.get_indexes(Book._meta.db_table),
|
||||
)
|
||||
# Alter to remove the index
|
||||
old_field = Book._meta.get_field("title")
|
||||
new_field = CharField(max_length=100, db_index=False)
|
||||
new_field.set_attributes_from_name("title")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Book,
|
||||
Book._meta.get_field("title"),
|
||||
new_field,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Book, old_field, new_field, strict=True)
|
||||
# Ensure the table is there and has no index
|
||||
self.assertNotIn(
|
||||
"title",
|
||||
self.get_indexes(Book._meta.db_table),
|
||||
)
|
||||
# Alter to re-add the index
|
||||
new_field2 = Book._meta.get_field("title")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
Book,
|
||||
new_field,
|
||||
Book._meta.get_field("title"),
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(Book, new_field, new_field2, strict=True)
|
||||
# Ensure the table is there and has the index again
|
||||
self.assertIn(
|
||||
"title",
|
||||
self.get_indexes(Book._meta.db_table),
|
||||
)
|
||||
# Add a unique column, verify that creates an implicit index
|
||||
new_field3 = BookWithSlug._meta.get_field("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
Book,
|
||||
BookWithSlug._meta.get_field("slug"),
|
||||
)
|
||||
editor.add_field(Book, new_field3)
|
||||
self.assertIn(
|
||||
"slug",
|
||||
self.get_indexes(Book._meta.db_table),
|
||||
)
|
||||
# Remove the unique, check the index goes with it
|
||||
new_field2 = CharField(max_length=20, unique=False)
|
||||
new_field2.set_attributes_from_name("slug")
|
||||
new_field4 = CharField(max_length=20, unique=False)
|
||||
new_field4.set_attributes_from_name("slug")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
BookWithSlug,
|
||||
BookWithSlug._meta.get_field("slug"),
|
||||
new_field2,
|
||||
strict=True,
|
||||
)
|
||||
editor.alter_field(BookWithSlug, new_field3, new_field4, strict=True)
|
||||
self.assertNotIn(
|
||||
"slug",
|
||||
self.get_indexes(Book._meta.db_table),
|
||||
|
@ -1138,16 +1115,14 @@ class SchemaTests(TransactionTestCase):
|
|||
self.get_indexes(Tag._meta.db_table)['id']['primary_key'],
|
||||
)
|
||||
# Alter to change the PK
|
||||
id_field = Tag._meta.get_field("id")
|
||||
old_field = Tag._meta.get_field("slug")
|
||||
new_field = SlugField(primary_key=True)
|
||||
new_field.set_attributes_from_name("slug")
|
||||
new_field.model = Tag
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_field(Tag, Tag._meta.get_field("id"))
|
||||
editor.alter_field(
|
||||
Tag,
|
||||
Tag._meta.get_field("slug"),
|
||||
new_field,
|
||||
)
|
||||
editor.remove_field(Tag, id_field)
|
||||
editor.alter_field(Tag, old_field, new_field)
|
||||
# Ensure the PK changed
|
||||
self.assertNotIn(
|
||||
'id',
|
||||
|
@ -1203,10 +1178,7 @@ class SchemaTests(TransactionTestCase):
|
|||
new_field = ForeignKey(AuthorWithEvenLongerName, related_name="something")
|
||||
new_field.set_attributes_from_name("author_other_really_long_named_i_mean_so_long_fk")
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
BookWithLongName,
|
||||
new_field,
|
||||
)
|
||||
editor.add_field(BookWithLongName, new_field)
|
||||
|
||||
def test_creation_deletion_reserved_names(self):
|
||||
"""
|
||||
|
@ -1305,50 +1277,6 @@ class SchemaTests(TransactionTestCase):
|
|||
item = cursor.fetchall()[0]
|
||||
self.assertEqual(item[0], None if connection.features.interprets_empty_strings_as_nulls else '')
|
||||
|
||||
def test_custom_manytomanyfield(self):
|
||||
"""
|
||||
#24104 - Schema editors should look for many_to_many
|
||||
"""
|
||||
# Create the tables
|
||||
with connection.schema_editor() as editor:
|
||||
editor.create_model(AuthorWithM2M)
|
||||
editor.create_model(TagM2MTest)
|
||||
# Create an M2M field
|
||||
new_field = CustomManyToManyField("schema.TagM2MTest", related_name="authors")
|
||||
new_field.contribute_to_class(AuthorWithM2M, "tags")
|
||||
# Ensure there's no m2m table there
|
||||
self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
|
||||
try:
|
||||
# Add the field
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_field(
|
||||
AuthorWithM2M,
|
||||
new_field,
|
||||
)
|
||||
# Ensure there is now an m2m table there
|
||||
columns = self.column_classes(new_field.rel.through)
|
||||
self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField")
|
||||
|
||||
# "Alter" the field. This should not rename the DB table to itself.
|
||||
with connection.schema_editor() as editor:
|
||||
editor.alter_field(
|
||||
AuthorWithM2M,
|
||||
new_field,
|
||||
new_field,
|
||||
)
|
||||
|
||||
# Remove the M2M table again
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_field(
|
||||
AuthorWithM2M,
|
||||
new_field,
|
||||
)
|
||||
# Ensure there's no m2m table there
|
||||
self.assertRaises(DatabaseError, self.column_classes, new_field.rel.through)
|
||||
finally:
|
||||
# Cleanup model states
|
||||
AuthorWithM2M._meta.local_many_to_many.remove(new_field)
|
||||
|
||||
def test_add_field_default_dropped(self):
|
||||
# Create the table
|
||||
with connection.schema_editor() as editor:
|
||||
|
|
Loading…
Reference in New Issue