Fixed #21236 -- Allowed migrations to work with unique_together tuples.
Thanks hjwp for the report.
This commit is contained in:
parent
67f5dffbec
commit
4dbd95ad65
|
@ -1,5 +1,6 @@
|
||||||
from .base import Operation
|
from .base import Operation
|
||||||
from django.db import models, router
|
from django.db import models, router
|
||||||
|
from django.db.models.options import normalize_unique_together
|
||||||
from django.db.migrations.state import ModelState
|
from django.db.migrations.state import ModelState
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,6 +109,7 @@ class AlterUniqueTogether(Operation):
|
||||||
|
|
||||||
def __init__(self, name, unique_together):
|
def __init__(self, name, unique_together):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
unique_together = normalize_unique_together(unique_together)
|
||||||
self.unique_together = set(tuple(cons) for cons in unique_together)
|
self.unique_together = set(tuple(cons) for cons in unique_together)
|
||||||
|
|
||||||
def state_forwards(self, app_label, state):
|
def state_forwards(self, app_label, state):
|
||||||
|
|
|
@ -25,6 +25,16 @@ DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering',
|
||||||
'index_together', 'app_cache', 'default_permissions',
|
'index_together', 'app_cache', 'default_permissions',
|
||||||
'select_on_save')
|
'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
|
@python_2_unicode_compatible
|
||||||
class Options(object):
|
class Options(object):
|
||||||
def __init__(self, meta, app_label=None):
|
def __init__(self, meta, app_label=None):
|
||||||
|
@ -108,13 +118,8 @@ class Options(object):
|
||||||
setattr(self, attr_name, getattr(self.meta, attr_name))
|
setattr(self, attr_name, getattr(self.meta, attr_name))
|
||||||
self.original_attrs[attr_name] = getattr(self, 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)
|
ut = meta_attrs.pop('unique_together', self.unique_together)
|
||||||
if ut and not isinstance(ut[0], (tuple, list)):
|
self.unique_together = normalize_unique_together(ut)
|
||||||
ut = (ut,)
|
|
||||||
self.unique_together = ut
|
|
||||||
|
|
||||||
# verbose_name_plural is a special case because it uses a 's'
|
# verbose_name_plural is a special case because it uses a 's'
|
||||||
# by default.
|
# by default.
|
||||||
|
|
|
@ -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 (1, 1, 1)")
|
||||||
cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)")
|
cursor.execute("INSERT INTO test_alunto_pony (id, pink, weight) VALUES (2, 1, 1)")
|
||||||
cursor.execute("DELETE FROM test_alunto_pony")
|
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):
|
def test_alter_index_together(self):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue