Loading django/db/migrations/operations/models.py +2 −0 Original line number Diff line number Diff line from .base import Operation from django.db import models, router from django.db.models.options import normalize_unique_together from django.db.migrations.state import ModelState Loading Loading @@ -108,6 +109,7 @@ class AlterUniqueTogether(Operation): def __init__(self, name, unique_together): self.name = name unique_together = normalize_unique_together(unique_together) self.unique_together = set(tuple(cons) for cons in unique_together) def state_forwards(self, app_label, state): Loading django/db/models/options.py +11 −6 Original line number Diff line number Diff line Loading @@ -25,6 +25,16 @@ DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 'index_together', 'app_cache', 'default_permissions', 'select_on_save') def normalize_unique_together(unique_together): """ unique_together can be either a tuple of tuples, or a single tuple of two strings. Normalize it to a tuple of tuples, so that calling code can uniformly expect that. """ if unique_together and not isinstance(unique_together[0], (tuple, list)): unique_together = (unique_together,) return unique_together @python_2_unicode_compatible class Options(object): def __init__(self, meta, app_label=None): Loading Loading @@ -108,13 +118,8 @@ class Options(object): setattr(self, attr_name, getattr(self.meta, attr_name)) self.original_attrs[attr_name] = getattr(self, attr_name) # unique_together can be either a tuple of tuples, or a single # tuple of two strings. Normalize it to a tuple of tuples, so that # calling code can uniformly expect that. ut = meta_attrs.pop('unique_together', self.unique_together) if ut and not isinstance(ut[0], (tuple, list)): ut = (ut,) self.unique_together = ut self.unique_together = normalize_unique_together(ut) # verbose_name_plural is a special case because it uses a 's' # by default. Loading tests/migrations/test_operations.py +4 −0 Original line number Diff line number Diff line Loading @@ -267,6 +267,10 @@ class OperationTests(MigrationTestBase): cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (1, 1, 1)") cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)") cursor.execute("DELETE FROM test_alunto_pony") # Test flat unique_together operation = migrations.AlterUniqueTogether("Pony", ("pink", "weight")) operation.state_forwards("test_alunto", new_state) self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1) def test_alter_index_together(self): """ Loading Loading
django/db/migrations/operations/models.py +2 −0 Original line number Diff line number Diff line from .base import Operation from django.db import models, router from django.db.models.options import normalize_unique_together from django.db.migrations.state import ModelState Loading Loading @@ -108,6 +109,7 @@ class AlterUniqueTogether(Operation): def __init__(self, name, unique_together): self.name = name unique_together = normalize_unique_together(unique_together) self.unique_together = set(tuple(cons) for cons in unique_together) def state_forwards(self, app_label, state): Loading
django/db/models/options.py +11 −6 Original line number Diff line number Diff line Loading @@ -25,6 +25,16 @@ DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 'index_together', 'app_cache', 'default_permissions', 'select_on_save') def normalize_unique_together(unique_together): """ unique_together can be either a tuple of tuples, or a single tuple of two strings. Normalize it to a tuple of tuples, so that calling code can uniformly expect that. """ if unique_together and not isinstance(unique_together[0], (tuple, list)): unique_together = (unique_together,) return unique_together @python_2_unicode_compatible class Options(object): def __init__(self, meta, app_label=None): Loading Loading @@ -108,13 +118,8 @@ class Options(object): setattr(self, attr_name, getattr(self.meta, attr_name)) self.original_attrs[attr_name] = getattr(self, attr_name) # unique_together can be either a tuple of tuples, or a single # tuple of two strings. Normalize it to a tuple of tuples, so that # calling code can uniformly expect that. ut = meta_attrs.pop('unique_together', self.unique_together) if ut and not isinstance(ut[0], (tuple, list)): ut = (ut,) self.unique_together = ut self.unique_together = normalize_unique_together(ut) # verbose_name_plural is a special case because it uses a 's' # by default. Loading
tests/migrations/test_operations.py +4 −0 Original line number Diff line number Diff line Loading @@ -267,6 +267,10 @@ class OperationTests(MigrationTestBase): cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (1, 1, 1)") cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)") cursor.execute("DELETE FROM test_alunto_pony") # Test flat unique_together operation = migrations.AlterUniqueTogether("Pony", ("pink", "weight")) operation.state_forwards("test_alunto", new_state) self.assertEqual(len(new_state.models["test_alunto", "pony"].options.get("unique_together", set())), 1) def test_alter_index_together(self): """ Loading