Fixed ModelState breaking when unique_together has unhashable elements.

This commit is contained in:
Baptiste Mispelon 2013-12-06 15:05:12 +01:00
parent 54d9e3ccf6
commit 19e4374971
3 changed files with 10 additions and 6 deletions

View File

@ -1,6 +1,6 @@
from django.db import models from django.db import models
from django.db.models.loading import BaseAppCache from django.db.models.loading import BaseAppCache
from django.db.models.options import DEFAULT_NAMES from django.db.models.options import DEFAULT_NAMES, normalize_unique_together
from django.utils import six from django.utils import six
from django.utils.module_loading import import_by_path from django.utils.module_loading import import_by_path
@ -127,7 +127,8 @@ class ModelState(object):
continue continue
elif name in model._meta.original_attrs: elif name in model._meta.original_attrs:
if name == "unique_together": if name == "unique_together":
options[name] = set(model._meta.original_attrs["unique_together"]) ut = model._meta.original_attrs["unique_together"]
options[name] = set(normalize_unique_together(ut))
else: else:
options[name] = model._meta.original_attrs[name] options[name] = model._meta.original_attrs[name]
# Make our record # Make our record

View File

@ -32,10 +32,13 @@ def normalize_unique_together(unique_together):
tuple of two strings. Normalize it to a tuple of tuples, so that tuple of two strings. Normalize it to a tuple of tuples, so that
calling code can uniformly expect that. calling code can uniformly expect that.
""" """
unique_together = tuple(unique_together) if not unique_together:
if unique_together and not isinstance(unique_together[0], (tuple, list)): return ()
first_element = next(iter(unique_together))
if not isinstance(first_element, (tuple, list)):
unique_together = (unique_together,) unique_together = (unique_together,)
return unique_together # Normalize everything to tuples
return tuple(tuple(ut) for ut in unique_together)
@python_2_unicode_compatible @python_2_unicode_compatible

View File

@ -55,7 +55,7 @@ class StateTests(TestCase):
self.assertEqual(author_state.fields[1][1].max_length, 255) self.assertEqual(author_state.fields[1][1].max_length, 255)
self.assertEqual(author_state.fields[2][1].null, False) self.assertEqual(author_state.fields[2][1].null, False)
self.assertEqual(author_state.fields[3][1].null, True) self.assertEqual(author_state.fields[3][1].null, True)
self.assertEqual(author_state.options, {"unique_together": set(("name", "bio"))}) self.assertEqual(author_state.options, {"unique_together": {("name", "bio")}})
self.assertEqual(author_state.bases, (models.Model, )) self.assertEqual(author_state.bases, (models.Model, ))
self.assertEqual(book_state.app_label, "migrations") self.assertEqual(book_state.app_label, "migrations")