diff --git a/django/db/models/options.py b/django/db/models/options.py index 502cbc4a65b..788d1c80dea 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -52,9 +52,19 @@ class Options(object): del meta_attrs['__doc__'] for attr_name in DEFAULT_NAMES: setattr(self, attr_name, meta_attrs.pop(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', getattr(self, 'unique_together')) + if ut and not isinstance(ut[0], (tuple, list)): + ut = (ut,) + setattr(self, 'unique_together', ut) + # verbose_name_plural is a special case because it uses a 's' # by default. setattr(self, 'verbose_name_plural', meta_attrs.pop('verbose_name_plural', string_concat(self.verbose_name, 's'))) + # Any leftover attributes must be invalid. if meta_attrs != {}: raise TypeError, "'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys()) diff --git a/docs/model-api.txt b/docs/model-api.txt index d6327bc7959..a8af05f676f 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -1226,6 +1226,13 @@ together. It's used in the Django admin and is enforced at the database level (i.e., the appropriate ``UNIQUE`` statements are included in the ``CREATE TABLE`` statement). +**New in Django development version** + +For convenience, unique_together can be a single list when dealing +with a single set of fields:: + + unique_together = ("driver", "restaurant") + ``verbose_name`` ----------------