Commit 331d79a7 authored by Baptiste Mispelon's avatar Baptiste Mispelon
Browse files

Fixed #21469 -- Allow set objects in Meta.unique_together.

Thanks to Tim for the review.
parent 4cfe6ba6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ def normalize_unique_together(unique_together):
    tuple of two strings. Normalize it to a tuple of tuples, so that
    calling code can uniformly expect that.
    """
    unique_together = tuple(unique_together)
    if unique_together and not isinstance(unique_together[0], (tuple, list)):
        unique_together = (unique_together,)
    return unique_together
+35 −1
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@ import datetime
import unittest

from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.loading import BaseAppCache
from django.test import TestCase

from .models import (CustomPKModel, UniqueTogetherModel, UniqueFieldsModel,
@@ -25,13 +27,45 @@ class GetUniqueCheckTests(unittest.TestCase):
    def test_unique_together_gets_picked_up_and_converted_to_tuple(self):
        m = UniqueTogetherModel()
        self.assertEqual(
            ([(UniqueTogetherModel, ('ifield', 'cfield',)),
            ([(UniqueTogetherModel, ('ifield', 'cfield')),
              (UniqueTogetherModel, ('ifield', 'efield')),
              (UniqueTogetherModel, ('id',)), ],
             []),
            m._get_unique_checks()
        )

    def test_unique_together_normalization(self):
        """
        Test the Meta.unique_together normalization with different sorts of
        objects.
        """
        data = {
            '2-tuple': (('foo', 'bar'),
                        (('foo', 'bar'),)),
            'list': (['foo', 'bar'],
                     (('foo', 'bar'),)),
            'already normalized': ((('foo', 'bar'), ('bar', 'baz')),
                                   (('foo', 'bar'), ('bar', 'baz'))),
            'set': ({('foo', 'bar'), ('bar', 'baz')},  # Ref #21469
                    (('foo', 'bar'), ('bar', 'baz'))),
        }

        for test_name, (unique_together, normalized) in data.items():
            class M(models.Model):
                foo = models.IntegerField()
                bar = models.IntegerField()
                baz = models.IntegerField()

                Meta = type(str('Meta'), (), {
                    'unique_together': unique_together,
                    'app_cache': BaseAppCache()
                })

            checks, _ = M()._get_unique_checks()
            for t in normalized:
                check = (M, t)
                self.assertIn(check, checks)

    def test_primary_key_is_considered_unique(self):
        m = CustomPKModel()
        self.assertEqual(([(CustomPKModel, ('my_pk_field',))], []), m._get_unique_checks())