diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index 1d6d9efa96..556a41ed83 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -855,6 +855,34 @@ class UniqueTest(TestCase): self.assertEqual(len(form.errors), 1) self.assertEqual(form.errors['__all__'], ['Price with this Price and Quantity already exists.']) + def test_unique_together_exclusion(self): + """ + Forms don't validate unique_together constraints when only part of the + constraint is included in the form's fields. This allows using + form.save(commit=False) and then assigning the missing field(s) to the + model instance. + """ + class BookForm(forms.ModelForm): + class Meta: + model = DerivedBook + fields = ('isbn', 'suffix1') + + # The unique_together is on suffix1/suffix2 but only suffix1 is part + # of the form. The fields must have defaults, otherwise they'll be + # skipped by other logic. + self.assertEqual(DerivedBook._meta.unique_together, (('suffix1', 'suffix2'),)) + for name in ('suffix1', 'suffix2'): + with self.subTest(name=name): + field = DerivedBook._meta.get_field(name) + self.assertEqual(field.default, 0) + + # The form fails validation with "Derived book with this Suffix1 and + # Suffix2 already exists." if the unique_together validation isn't + # skipped. + DerivedBook.objects.create(isbn='12345') + form = BookForm({'isbn': '56789', 'suffix1': '0'}) + self.assertTrue(form.is_valid(), form.errors) + def test_multiple_field_unique_together(self): """ When the same field is involved in multiple unique_together